diff --git a/.changeset/young-carrots-burn.md b/.changeset/young-carrots-burn.md new file mode 100644 index 00000000000..d5edf4799bf --- /dev/null +++ b/.changeset/young-carrots-burn.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +ERC20 assets diff --git a/package.json b/package.json index e55b9a6d91b..246a3cf8ba6 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,5 @@ "wallet-ui": "turbo run dev --filter=./apps/wallet-ui --filter=./packages/thirdweb --filter=./packages/insight --filter=./packages/engine --filter=./packages/nebula", "wallet-ui:build": "turbo run build --filter=./apps/wallet-ui --filter=./packages/thirdweb --filter=./packages/insight --filter=./packages/engine --filter=./packages/nebula" }, - "version": "1.0.0" } diff --git a/packages/thirdweb/package.json b/packages/thirdweb/package.json index 605c5ca7256..1c7cff9576b 100644 --- a/packages/thirdweb/package.json +++ b/packages/thirdweb/package.json @@ -97,128 +97,133 @@ }, "exports": { ".": { - "types": "./dist/types/exports/thirdweb.d.ts", + "default": "./dist/cjs/exports/thirdweb.js", "import": "./dist/esm/exports/thirdweb.js", - "default": "./dist/cjs/exports/thirdweb.js" + "types": "./dist/types/exports/thirdweb.d.ts" }, "./adapters/*": { - "types": "./dist/types/exports/adapters/*.d.ts", + "default": "./dist/cjs/exports/adapters/*.js", "import": "./dist/esm/exports/adapters/*.js", - "default": "./dist/cjs/exports/adapters/*.js" + "types": "./dist/types/exports/adapters/*.d.ts" }, "./ai": { - "types": "./dist/types/exports/ai.d.ts", + "default": "./dist/cjs/exports/ai.js", "import": "./dist/esm/exports/ai.js", - "default": "./dist/cjs/exports/ai.js" + "types": "./dist/types/exports/ai.d.ts" + }, + "./assets": { + "default": "./dist/cjs/exports/assets.js", + "import": "./dist/esm/exports/assets.js", + "types": "./dist/types/exports/assets.d.ts" }, "./auth": { - "types": "./dist/types/exports/auth.d.ts", + "default": "./dist/cjs/exports/auth.js", "import": "./dist/esm/exports/auth.js", - "default": "./dist/cjs/exports/auth.js" + "types": "./dist/types/exports/auth.d.ts" }, "./bridge": { - "types": "./dist/types/exports/bridge.d.ts", + "default": "./dist/cjs/exports/bridge.js", "import": "./dist/esm/exports/bridge.js", - "default": "./dist/cjs/exports/bridge.js" + "types": "./dist/types/exports/bridge.d.ts" }, "./chains": { - "types": "./dist/types/exports/chains.d.ts", + "default": "./dist/cjs/exports/chains.js", "import": "./dist/esm/exports/chains.js", - "default": "./dist/cjs/exports/chains.js" + "types": "./dist/types/exports/chains.d.ts" }, "./contract": { - "types": "./dist/types/exports/contract.d.ts", + "default": "./dist/cjs/exports/contract.js", "import": "./dist/esm/exports/contract.js", - "default": "./dist/cjs/exports/contract.js" + "types": "./dist/types/exports/contract.d.ts" }, "./deploys": { - "types": "./dist/types/exports/deploys.d.ts", + "default": "./dist/cjs/exports/deploys.js", "import": "./dist/esm/exports/deploys.js", - "default": "./dist/cjs/exports/deploys.js" + "types": "./dist/types/exports/deploys.d.ts" }, "./engine": { - "types": "./dist/types/exports/engine.d.ts", + "default": "./dist/cjs/exports/engine.js", "import": "./dist/esm/exports/engine.js", - "default": "./dist/cjs/exports/engine.js" + "types": "./dist/types/exports/engine.d.ts" }, "./event": { - "types": "./dist/types/exports/event.d.ts", + "default": "./dist/cjs/exports/event.js", "import": "./dist/esm/exports/event.js", - "default": "./dist/cjs/exports/event.js" + "types": "./dist/types/exports/event.d.ts" }, "./extensions/*": { - "types": "./dist/types/exports/extensions/*.d.ts", + "default": "./dist/cjs/exports/extensions/*.js", "import": "./dist/esm/exports/extensions/*.js", - "default": "./dist/cjs/exports/extensions/*.js" + "types": "./dist/types/exports/extensions/*.d.ts" }, "./insight": { - "types": "./dist/types/exports/insight.d.ts", + "default": "./dist/cjs/exports/insight.js", "import": "./dist/esm/exports/insight.js", - "default": "./dist/cjs/exports/insight.js" + "types": "./dist/types/exports/insight.d.ts" }, "./modules": { - "types": "./dist/types/exports/modules.d.ts", + "default": "./dist/cjs/exports/modules.js", "import": "./dist/esm/exports/modules.js", - "default": "./dist/cjs/exports/modules.js" + "types": "./dist/types/exports/modules.d.ts" }, "./package.json": "./package.json", "./pay": { - "types": "./dist/types/exports/pay.d.ts", + "default": "./dist/cjs/exports/pay.js", "import": "./dist/esm/exports/pay.js", - "default": "./dist/cjs/exports/pay.js" + "types": "./dist/types/exports/pay.d.ts" }, "./react": { - "types": "./dist/types/exports/react.d.ts", - "react-native": "./dist/esm/exports/react.native.js", + "default": "./dist/cjs/exports/react.js", "import": "./dist/esm/exports/react.js", - "default": "./dist/cjs/exports/react.js" + "react-native": "./dist/esm/exports/react.native.js", + "types": "./dist/types/exports/react.d.ts" }, "./react-native": { - "types": "./dist/types/exports/react.native.d.ts", + "default": "./dist/cjs/exports/react.native.js", "import": "./dist/esm/exports/react.native.js", - "default": "./dist/cjs/exports/react.native.js" + "types": "./dist/types/exports/react.native.d.ts" }, "./rpc": { - "types": "./dist/types/exports/rpc.d.ts", + "default": "./dist/cjs/exports/rpc.js", "import": "./dist/esm/exports/rpc.js", - "default": "./dist/cjs/exports/rpc.js" + "types": "./dist/types/exports/rpc.d.ts" }, "./social": { - "types": "./dist/types/exports/social.d.ts", + "default": "./dist/cjs/exports/social.js", "import": "./dist/esm/exports/social.js", - "default": "./dist/cjs/exports/social.js" + "types": "./dist/types/exports/social.d.ts" }, "./storage": { - "types": "./dist/types/exports/storage.d.ts", + "default": "./dist/cjs/exports/storage.js", "import": "./dist/esm/exports/storage.js", - "default": "./dist/cjs/exports/storage.js" + "types": "./dist/types/exports/storage.d.ts" }, "./transaction": { - "types": "./dist/types/exports/transaction.d.ts", + "default": "./dist/cjs/exports/transaction.js", "import": "./dist/esm/exports/transaction.js", - "default": "./dist/cjs/exports/transaction.js" + "types": "./dist/types/exports/transaction.d.ts" }, "./utils": { - "types": "./dist/types/exports/utils.d.ts", + "default": "./dist/cjs/exports/utils.js", "import": "./dist/esm/exports/utils.js", - "default": "./dist/cjs/exports/utils.js" + "types": "./dist/types/exports/utils.d.ts" }, "./wallets": { - "types": "./dist/types/exports/wallets.d.ts", - "react-native": "./dist/esm/exports/wallets.native.js", + "default": "./dist/cjs/exports/wallets.js", "import": "./dist/esm/exports/wallets.js", - "default": "./dist/cjs/exports/wallets.js" + "react-native": "./dist/esm/exports/wallets.native.js", + "types": "./dist/types/exports/wallets.d.ts" }, "./wallets/*": { - "types": "./dist/types/exports/wallets/*.d.ts", + "default": "./dist/cjs/exports/wallets/*.js", "import": "./dist/esm/exports/wallets/*.js", - "default": "./dist/cjs/exports/wallets/*.js" + "types": "./dist/types/exports/wallets/*.d.ts" }, "./wallets/in-app": { - "types": "./dist/types/exports/wallets/in-app.d.ts", - "react-native": "./dist/esm/exports/wallets/in-app.native.js", + "default": "./dist/cjs/exports/wallets/in-app.js", "import": "./dist/esm/exports/wallets/in-app.js", - "default": "./dist/cjs/exports/wallets/in-app.js" + "react-native": "./dist/esm/exports/wallets/in-app.native.js", + "types": "./dist/types/exports/wallets/in-app.d.ts" } }, "files": [ @@ -347,6 +352,9 @@ "ai": [ "./dist/types/exports/ai.d.ts" ], + "assets": [ + "./dist/types/exports/assets.d.ts" + ], "auth": [ "./dist/types/exports/auth.d.ts" ], diff --git a/packages/thirdweb/scripts/generate/abis/assets/AssetEntrypointERC20.json b/packages/thirdweb/scripts/generate/abis/assets/AssetEntrypointERC20.json new file mode 100644 index 00000000000..fb70492cbb3 --- /dev/null +++ b/packages/thirdweb/scripts/generate/abis/assets/AssetEntrypointERC20.json @@ -0,0 +1,34 @@ +[ + "function initialize(address _owner, address _router, address _rewardLocker)", + "function setRouter(address router)", + "function getRouter() external view returns (address router)", + "function setRewardLocker(address rewardLocker)", + "function getRewardLocker() external view returns (address rewardLocker)", + "function addImplementation((bytes32 contractId, address implementation, uint8 implementationType, uint8 createHook, bytes createHookData) config, bool isDefault)", + "function getImplementation(bytes32 contractId) external view returns ((bytes32 contractId, address implementation, uint8 implementationType, uint8 createHook, bytes createHookData))", + "function createAsset(address creator, (uint256 amount, address referrer, bytes32 salt, bytes data, bytes hookData) createParams) external returns (address asset)", + "function createAssetById(bytes32 contractId, address creator, (uint256 amount, address referrer, bytes32 salt, bytes data, bytes hookData) params) public returns (address asset)", + "function createAssetByImplementationConfig((bytes32 contractId, address implementation, uint8 implementationType, uint8 createHook, bytes createHookData) config, address creator, (uint256 amount, address referrer, bytes32 salt, bytes data, bytes hookData) params) external returns (address asset)", + "function buyAsset(address asset, (address recipient, address referrer, address tokenIn, uint256 amountIn, uint256 minAmountOut, uint256 deadline, bytes data) params) external payable returns (uint256 amountIn, uint256 amountOut)", + "function sellAsset(address asset, (address recipient, address tokenOut, uint256 amountIn, uint256 minAmountOut, uint256 deadline, bytes data) params) external returns (uint256 amountIn, uint256 amountOut)", + "function listAsset(address asset, (address tokenIn, uint256 price, uint256 duration, bytes data) params) external", + "function distributeAsset(address asset, (uint256 amount, address recipient)[] contents) external payable", + "event ImplementationAdded(bytes32 contractId, address indexed implementation, uint8 implementationType, uint8 createHook, bytes32 createHookData)", + "event RouterUpdated(address indexed router)", + "event RewardLockerUpdated(address indexed locker)", + "event AssetCreated(bytes32 contractId, address indexed creator, address indexed asset, address referrer, bytes aux)", + "event AssetDistributed(address asset, uint256 recipientCount, uint256 totalAmount)", + "error InvalidValue()", + "error InvalidContractId()", + "error ValueTransferFailed()", + "error ArrayLengthMismatch()", + "error AssetNotRegistered()", + "error InvalidCreator()", + "error InvalidInitializer()", + "error InvalidImplementation()", + "error InvalidDeploymentArgs()", + "error InvalidCreateHook()", + "error CreateHookFailed()", + "error CreateHookReverted(string reason)", + "error ImplementationAlreadyExists()" +] \ No newline at end of file diff --git a/packages/thirdweb/scripts/generate/abis/assets/AssetInfraDeployer.json b/packages/thirdweb/scripts/generate/abis/assets/AssetInfraDeployer.json new file mode 100644 index 00000000000..766a994a655 --- /dev/null +++ b/packages/thirdweb/scripts/generate/abis/assets/AssetInfraDeployer.json @@ -0,0 +1,5 @@ +[ + "function deployInfraProxyDeterministic(address implementation, bytes data, bytes32 salt, bytes extraData) public returns (address deployedProxy)", + "event AssetInfraDeployed(address indexed implementation, address indexed proxy, bytes32 inputSalt, bytes data, bytes extraData)", + "error ProxyDeploymentFailed()" +] \ No newline at end of file diff --git a/packages/thirdweb/scripts/generate/abis/assets/ERC20Asset.json b/packages/thirdweb/scripts/generate/abis/assets/ERC20Asset.json new file mode 100644 index 00000000000..ca2259afcf3 --- /dev/null +++ b/packages/thirdweb/scripts/generate/abis/assets/ERC20Asset.json @@ -0,0 +1,3 @@ +[ + "function initialize(string _name, string _symbol, string _contractURI, uint256 _maxSupply, address _owner) external" +] \ No newline at end of file diff --git a/packages/thirdweb/scripts/generate/abis/assets/FeeManager.json b/packages/thirdweb/scripts/generate/abis/assets/FeeManager.json new file mode 100644 index 00000000000..f4673cf7699 --- /dev/null +++ b/packages/thirdweb/scripts/generate/abis/assets/FeeManager.json @@ -0,0 +1,3 @@ +[ + "function initialize(address _owner, address _feeRecipient, uint96 _defaultFee) external" +] \ No newline at end of file diff --git a/packages/thirdweb/scripts/generate/abis/assets/Router.json b/packages/thirdweb/scripts/generate/abis/assets/Router.json new file mode 100644 index 00000000000..15e07b4d6b5 --- /dev/null +++ b/packages/thirdweb/scripts/generate/abis/assets/Router.json @@ -0,0 +1,3 @@ +[ + "function initialize(address _owner) external" +] \ No newline at end of file diff --git a/packages/thirdweb/src/assets/bootstrap.ts b/packages/thirdweb/src/assets/bootstrap.ts new file mode 100644 index 00000000000..6d52bdb1ccd --- /dev/null +++ b/packages/thirdweb/src/assets/bootstrap.ts @@ -0,0 +1,331 @@ +import { encodePacked } from "viem"; +import { ZERO_ADDRESS } from "../constants/addresses.js"; +import { getContract } from "../contract/contract.js"; +import { getOrDeployInfraContract } from "../contract/deployment/utils/bootstrap.js"; +import { + deployCreate2Factory, + getDeployedCreate2Factory, +} from "../contract/deployment/utils/create-2-factory.js"; +import { getDeployedInfraContract } from "../contract/deployment/utils/infra.js"; +import { parseEventLogs } from "../event/actions/parse-logs.js"; +import { assetInfraDeployedEvent } from "../extensions/assets/__generated__/AssetInfraDeployer/events/AssetInfraDeployed.js"; +import { deployInfraProxyDeterministic } from "../extensions/assets/__generated__/AssetInfraDeployer/write/deployInfraProxyDeterministic.js"; +import { encodeInitialize as encodeFeeManagerInit } from "../extensions/assets/__generated__/FeeManager/write/initialize.js"; +import { encodeInitialize as encodeRouterInit } from "../extensions/assets/__generated__/Router/write/initialize.js"; +import { sendAndConfirmTransaction } from "../transaction/actions/send-and-confirm-transaction.js"; +import { keccakId } from "../utils/any-evm/keccak-id.js"; +import { isContractDeployed } from "../utils/bytecode/is-contract-deployed.js"; +import { keccak256 } from "../utils/hashing/keccak256.js"; +import type { + ClientAndChain, + ClientAndChainAndAccount, +} from "../utils/types.js"; +import { + DEFAULT_FEE_BPS, + DEFAULT_FEE_RECIPIENT, + DEFAULT_INFRA_ADMIN, + DEFAULT_SALT, + IMPLEMENTATIONS, +} from "./constants.js"; +import { deployInfraProxy } from "./deploy-infra-proxy.js"; +import { getInitCodeHashERC1967 } from "./get-initcode-hash-1967.js"; + +export async function deployRouter(options: ClientAndChainAndAccount) { + let [feeManager, marketSaleImpl] = await Promise.all([ + getDeployedFeeManager(options), + getDeployedInfraContract({ + ...options, + contractId: "MarketSale", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }), + ]); + + if (!feeManager) { + feeManager = await deployFeeManager(options); + } + + if (!marketSaleImpl) { + marketSaleImpl = await getOrDeployInfraContract({ + ...options, + contractId: "MarketSale", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }); + } + + const assetFactory = await getDeployedAssetFactory(options); + if (!assetFactory) { + throw new Error(`Asset factory not found for chain: ${options.chain.id}`); + } + + const routerImpl = await getOrDeployInfraContract({ + ...options, + constructorParams: { + _feeManager: feeManager.address, + _marketSaleImplementation: marketSaleImpl.address, + }, + contractId: "Router", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }); + + // encode init data + const initData = encodeRouterInit({ + owner: DEFAULT_INFRA_ADMIN, + }); + + const routerProxyAddress = await deployInfraProxy({ + ...options, + assetFactory, + extraData: "0x", + implementationAddress: routerImpl.address, + initData, + }); + + return getContract({ + address: routerProxyAddress, + chain: options.chain, + client: options.client, + }); +} + +export async function deployRewardLocker(options: ClientAndChainAndAccount) { + let v3PositionManager = ZERO_ADDRESS; + let v4PositionManager = ZERO_ADDRESS; + + const implementations = IMPLEMENTATIONS[options.chain.id]; + + if (implementations) { + v3PositionManager = implementations.V3PositionManager || ZERO_ADDRESS; + v4PositionManager = implementations.V4PositionManager || ZERO_ADDRESS; + } + + let feeManager = await getDeployedFeeManager(options); + + if (!feeManager) { + feeManager = await deployFeeManager(options); + } + + return await getOrDeployInfraContract({ + ...options, + constructorParams: { + _feeManager: feeManager.address, + _v3PositionManager: v3PositionManager, + _v4PositionManager: v4PositionManager, + }, + contractId: "RewardLocker", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }); +} + +export async function deployFeeManager(options: ClientAndChainAndAccount) { + // asset factory + let assetFactory = await getDeployedAssetFactory(options); + if (!assetFactory) { + assetFactory = await deployAssetFactory(options); + } + + // fee manager implementation + const feeManagerImpl = await getOrDeployInfraContract({ + ...options, + contractId: "FeeManager", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }); + + // encode init data + const initData = encodeFeeManagerInit({ + defaultFee: DEFAULT_FEE_BPS, + feeRecipient: DEFAULT_FEE_RECIPIENT, + owner: DEFAULT_INFRA_ADMIN, + }); + + // fee manager proxy deployment + const transaction = deployInfraProxyDeterministic({ + contract: assetFactory, + data: initData, + extraData: "0x", + implementation: feeManagerImpl.address, + salt: keccakId(DEFAULT_SALT), + }); + + const receipt = await sendAndConfirmTransaction({ + account: options.account, + transaction, + }); + const proxyEvent = assetInfraDeployedEvent(); + const decodedEvent = parseEventLogs({ + events: [proxyEvent], + logs: receipt.logs, + }); + + if (decodedEvent.length === 0 || !decodedEvent[0]) { + throw new Error( + `No AssetInfraDeployed event found in transaction: ${receipt.transactionHash}`, + ); + } + + const feeManagerProxyAddress = decodedEvent[0]?.args.proxy; + + return getContract({ + address: feeManagerProxyAddress, + chain: options.chain, + client: options.client, + }); +} + +export async function deployAssetFactory(options: ClientAndChainAndAccount) { + // create2 factory + const create2Factory = await getDeployedCreate2Factory(options); + if (!create2Factory) { + await deployCreate2Factory(options); + } + + // asset factory + return getOrDeployInfraContract({ + ...options, + contractId: "AssetInfraDeployer", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }); +} + +export async function getDeployedRouter(options: ClientAndChain) { + const [feeManager, marketSaleImpl, assetFactory] = await Promise.all([ + getDeployedFeeManager(options), + getDeployedInfraContract({ + ...options, + contractId: "MarketSale", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }), + getDeployedAssetFactory(options), + ]); + + if (!feeManager || !marketSaleImpl || !assetFactory) { + return null; + } + + const routerImpl = await getDeployedInfraContract({ + ...options, + constructorParams: { + _feeManager: feeManager.address, + _marketSaleImplementation: marketSaleImpl.address, + }, + contractId: "Router", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }); + + if (!routerImpl) { + return null; + } + + const initCodeHash = getInitCodeHashERC1967(routerImpl.address); + + const saltHash = keccak256( + encodePacked( + ["bytes32", "address"], + [keccakId(DEFAULT_SALT), DEFAULT_INFRA_ADMIN], + ), + ); + + const hashedDeployInfo = keccak256( + encodePacked( + ["bytes1", "address", "bytes32", "bytes32"], + ["0xff", assetFactory.address, saltHash, initCodeHash], + ), + ); + + const routerProxyAddress = `0x${hashedDeployInfo.slice(26)}`; + const routerProxy = getContract({ + address: routerProxyAddress, + chain: options.chain, + client: options.client, + }); + + if (!(await isContractDeployed(routerProxy))) { + return null; + } + + return routerProxy; +} + +export async function getDeployedRewardLocker(options: ClientAndChain) { + let v3PositionManager = ZERO_ADDRESS; + let v4PositionManager = ZERO_ADDRESS; + + const implementations = IMPLEMENTATIONS[options.chain.id]; + + if (implementations) { + v3PositionManager = implementations.V3PositionManager || ZERO_ADDRESS; + v4PositionManager = implementations.V4PositionManager || ZERO_ADDRESS; + } + + const feeManager = await getDeployedFeeManager(options); + + if (!feeManager) { + return null; + } + + return await getDeployedInfraContract({ + ...options, + constructorParams: { + _feeManager: feeManager.address, + _v3PositionManager: v3PositionManager, + _v4PositionManager: v4PositionManager, + }, + contractId: "RewardLocker", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }); +} + +export async function getDeployedFeeManager(options: ClientAndChain) { + const [assetFactory, feeManagerImpl] = await Promise.all([ + getDeployedAssetFactory(options), + getDeployedInfraContract({ + ...options, + contractId: "FeeManager", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }), + ]); + + if (!assetFactory || !feeManagerImpl) { + return null; + } + + const initCodeHash = getInitCodeHashERC1967(feeManagerImpl.address); + + const saltHash = keccak256( + encodePacked( + ["bytes32", "address"], + [keccakId(DEFAULT_SALT), DEFAULT_INFRA_ADMIN], + ), + ); + + const hashedDeployInfo = keccak256( + encodePacked( + ["bytes1", "address", "bytes32", "bytes32"], + ["0xff", assetFactory.address, saltHash, initCodeHash], + ), + ); + + const feeManagerProxyAddress = `0x${hashedDeployInfo.slice(26)}`; + const feeManagerProxy = getContract({ + address: feeManagerProxyAddress, + chain: options.chain, + client: options.client, + }); + + if (!(await isContractDeployed(feeManagerProxy))) { + return null; + } + + return feeManagerProxy; +} + +export async function getDeployedAssetFactory(args: ClientAndChain) { + const assetFactory = await getDeployedInfraContract({ + ...args, + contractId: "AssetInfraDeployer", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }); + if (!assetFactory) { + return null; + } + return assetFactory; +} diff --git a/packages/thirdweb/src/assets/bootstrapinfra.test.ts b/packages/thirdweb/src/assets/bootstrapinfra.test.ts new file mode 100644 index 00000000000..936652de893 --- /dev/null +++ b/packages/thirdweb/src/assets/bootstrapinfra.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from "vitest"; +import { ANVIL_CHAIN } from "../../test/src/chains.js"; +import { TEST_CLIENT } from "../../test/src/test-clients.js"; +import { TEST_ACCOUNT_A } from "../../test/src/test-wallets.js"; +import { deployFeeManager, getDeployedFeeManager } from "./bootstrap.js"; + +describe.runIf(process.env.TW_SECRET_KEY)("bootstrap asset infra", () => { + it("should bootstrap fee manager", async () => { + const feeManager = await deployFeeManager({ + account: TEST_ACCOUNT_A, + chain: ANVIL_CHAIN, + client: TEST_CLIENT, + }); + + const expectedFeeManager = await getDeployedFeeManager({ + chain: ANVIL_CHAIN, + client: TEST_CLIENT, + }); + + expect(expectedFeeManager).toBeDefined(); + expect(feeManager.address.toLowerCase()).to.equal( + expectedFeeManager?.address?.toLowerCase(), + ); + }); +}); diff --git a/packages/thirdweb/src/assets/constants.ts b/packages/thirdweb/src/assets/constants.ts new file mode 100644 index 00000000000..7069f63c20f --- /dev/null +++ b/packages/thirdweb/src/assets/constants.ts @@ -0,0 +1,38 @@ +export const DEFAULT_MAX_SUPPLY_ERC20 = 10_000_000_000n; +export const DEFAULT_POOL_FEE = 10000; +export const DEFAULT_POOL_INITIAL_TICK = 230200; +export const DEFAULT_INFRA_ADMIN = "0x1a472863cf21d5aa27f417df9140400324c48f22"; +export const DEFAULT_FEE_RECIPIENT = + "0x1af20c6b23373350ad464700b5965ce4b0d2ad94"; +export const DEFAULT_FEE_BPS = 50n; +export const DEFAULT_SALT = "thirdweb"; + +export const IMPLEMENTATIONS: Record> = { + 8453: { + AssetEntrypointERC20: "0x7FF679bFb89ee0F88645CAb8Ab0844ea485a3434", + ERC20AssetImpl: "", + V3PositionManager: "", + V4PositionManager: "", + }, + 84532: { + AssetEntrypointERC20: "0x79C1236cFe59f1f088A15Da08b0D8667387d9703", + ERC20AssetImpl: "", + V3PositionManager: "", + V4PositionManager: "", + }, +}; + +export enum ImplementationType { + CLONE = 0, + CLONE_WITH_IMMUTABLE_ARGS = 1, + ERC1967 = 2, + ERC1967_WITH_IMMUTABLE_ARGS = 3, +} + +export enum CreateHook { + NONE = 0, // do nothing + CREATE_POOL = 1, // create a DEX pool via Router + CREATE_MARKET = 2, // create a market sale via Router + DISTRIBUTE = 3, // distribute tokens to recipients + EXTERNAL_HOOK = 4, // call an external hook contract +} diff --git a/packages/thirdweb/src/assets/create-token-by-impl-config.ts b/packages/thirdweb/src/assets/create-token-by-impl-config.ts new file mode 100644 index 00000000000..96460b0ff72 --- /dev/null +++ b/packages/thirdweb/src/assets/create-token-by-impl-config.ts @@ -0,0 +1,130 @@ +import type { Hex } from "viem"; +import { NATIVE_TOKEN_ADDRESS, ZERO_ADDRESS } from "../constants/addresses.js"; +import { getContract } from "../contract/contract.js"; +import { parseEventLogs } from "../event/actions/parse-logs.js"; +import { assetCreatedEvent } from "../extensions/assets/__generated__/AssetEntrypointERC20/events/AssetCreated.js"; +import { createAssetByImplementationConfig } from "../extensions/assets/__generated__/AssetEntrypointERC20/write/createAssetByImplementationConfig.js"; +import { decimals } from "../extensions/erc20/read/decimals.js"; +import { eth_blockNumber } from "../rpc/actions/eth_blockNumber.js"; +import { getRpcClient } from "../rpc/rpc.js"; +import { sendAndConfirmTransaction } from "../transaction/actions/send-and-confirm-transaction.js"; +import { keccakId } from "../utils/any-evm/keccak-id.js"; +import { toHex } from "../utils/encoding/hex.js"; +import { toUnits } from "../utils/units.js"; +import { + CreateHook, + DEFAULT_MAX_SUPPLY_ERC20, + ImplementationType, +} from "./constants.js"; +import { getOrDeployEntrypointERC20 } from "./get-entrypoint-erc20.js"; +import { getOrDeployERC20AssetImpl } from "./get-erc20-asset-impl.js"; +import { + encodeInitParams, + encodeMarketConfig, + encodePoolConfig, +} from "./token-utils.js"; +import type { CreateTokenOptions } from "./types.js"; + +export async function createTokenByImplConfig(options: CreateTokenOptions) { + const { client, chain, account, params, launchConfig } = options; + + const creator = params.owner || account.address; + + const encodedInitData = await encodeInitParams({ + client, + creator, + params, + }); + + const rpcRequest = getRpcClient({ + ...options, + }); + const blockNumber = await eth_blockNumber(rpcRequest); + const salt = options.salt + ? options.salt.startsWith("0x") && options.salt.length === 66 + ? (options.salt as `0x${string}`) + : keccakId(options.salt) + : toHex(blockNumber, { + size: 32, + }); + + const entrypoint = await getOrDeployEntrypointERC20(options); + const tokenImpl = await getOrDeployERC20AssetImpl(options); + + let hookData: Hex = "0x"; + let amount = toUnits( + params.maxSupply.toString() || DEFAULT_MAX_SUPPLY_ERC20.toString(), + 18, + ); + if (launchConfig?.kind === "pool") { + hookData = encodePoolConfig(launchConfig.config); + amount = toUnits( + launchConfig.config.amount.toString() || + DEFAULT_MAX_SUPPLY_ERC20.toString(), + 18, + ); + } else if (launchConfig?.kind === "market") { + const currencyContract = + launchConfig.config.tokenOut && + launchConfig.config.tokenOut !== NATIVE_TOKEN_ADDRESS + ? getContract({ + address: launchConfig.config.tokenOut, + chain, + client, + }) + : null; + const currencyDecimals = launchConfig.config.priceDenominator + ? launchConfig.config.priceDenominator + : currencyContract + ? await decimals({ + contract: currencyContract, + }) + : 18; + + hookData = encodeMarketConfig({ + ...launchConfig.config, + decimals: currencyDecimals, + }); + } + + const transaction = createAssetByImplementationConfig({ + config: { + contractId: keccakId("ERC20Asset"), + createHook: + launchConfig?.kind === "pool" + ? CreateHook.CREATE_POOL + : launchConfig?.kind === "market" + ? CreateHook.CREATE_MARKET + : launchConfig?.kind === "distribute" + ? CreateHook.DISTRIBUTE + : CreateHook.NONE, + createHookData: hookData, + implementation: tokenImpl.address, + implementationType: ImplementationType.ERC1967, + }, + contract: entrypoint, + creator, + params: { + amount, + data: encodedInitData, + hookData, + referrer: ZERO_ADDRESS, + salt, + }, + }); + + const receipt = await sendAndConfirmTransaction({ account, transaction }); + const assetEvent = assetCreatedEvent(); + const decodedEvent = parseEventLogs({ + events: [assetEvent], + logs: receipt.logs, + }); + + if (decodedEvent.length === 0 || !decodedEvent[0]) { + throw new Error( + `No AssetCreated event found in transaction: ${receipt.transactionHash}`, + ); + } + + return decodedEvent[0]?.args.asset; +} diff --git a/packages/thirdweb/src/assets/create-token.test.ts b/packages/thirdweb/src/assets/create-token.test.ts new file mode 100644 index 00000000000..6749404c7b7 --- /dev/null +++ b/packages/thirdweb/src/assets/create-token.test.ts @@ -0,0 +1,44 @@ +import { describe, expect, it } from "vitest"; +import { ANVIL_CHAIN } from "../../test/src/chains.js"; +import { TEST_CLIENT } from "../../test/src/test-clients.js"; +import { TEST_ACCOUNT_A } from "../../test/src/test-wallets.js"; +import { getContract } from "../contract/contract.js"; +import { name } from "../extensions/common/read/name.js"; +// import { totalSupply } from "../extensions/erc20/__generated__/IERC20/read/totalSupply.js"; +import { createTokenByImplConfig } from "./create-token-by-impl-config.js"; + +describe.runIf(process.env.TW_SECRET_KEY)("create token by impl config", () => { + it("should create token without pool", async () => { + const token = await createTokenByImplConfig({ + account: TEST_ACCOUNT_A, + chain: ANVIL_CHAIN, + client: TEST_CLIENT, + params: { + maxSupply: 10_00n, + name: "Test", + }, + salt: "salt123", + }); + + expect(token).toBeDefined(); + + const tokenName = await name({ + contract: getContract({ + address: token, + chain: ANVIL_CHAIN, + client: TEST_CLIENT, + }), + }); + expect(tokenName).to.eq("Test"); + + // const supply = await totalSupply({ + // contract: getContract({ + // client: TEST_CLIENT, + // chain: ANVIL_CHAIN, + // address: token, + // }), + // }); + + // console.log("supply: ", supply); + }); +}); diff --git a/packages/thirdweb/src/assets/create-token.ts b/packages/thirdweb/src/assets/create-token.ts new file mode 100644 index 00000000000..9bc6d09f947 --- /dev/null +++ b/packages/thirdweb/src/assets/create-token.ts @@ -0,0 +1,110 @@ +import type { Hex } from "viem"; +import { NATIVE_TOKEN_ADDRESS, ZERO_ADDRESS } from "../constants/addresses.js"; +import { getContract } from "../contract/contract.js"; +import { parseEventLogs } from "../event/actions/parse-logs.js"; +import { assetCreatedEvent } from "../extensions/assets/__generated__/AssetEntrypointERC20/events/AssetCreated.js"; +import { createAsset } from "../extensions/assets/__generated__/AssetEntrypointERC20/write/createAsset.js"; +import { decimals } from "../extensions/erc20/read/decimals.js"; +import { eth_blockNumber } from "../rpc/actions/eth_blockNumber.js"; +import { getRpcClient } from "../rpc/rpc.js"; +import { sendAndConfirmTransaction } from "../transaction/actions/send-and-confirm-transaction.js"; +import { keccakId } from "../utils/any-evm/keccak-id.js"; +import { toHex } from "../utils/encoding/hex.js"; +import { toUnits } from "../utils/units.js"; +import { DEFAULT_MAX_SUPPLY_ERC20 } from "./constants.js"; +import { getOrDeployEntrypointERC20 } from "./get-entrypoint-erc20.js"; +import { + encodeInitParams, + encodeMarketConfig, + encodePoolConfig, +} from "./token-utils.js"; +import type { CreateTokenOptions } from "./types.js"; + +export async function createToken(options: CreateTokenOptions) { + const { client, chain, account, params, launchConfig } = options; + + const creator = params.owner || account.address; + + const encodedInitData = await encodeInitParams({ + client, + creator, + params, + }); + + const rpcRequest = getRpcClient({ + ...options, + }); + const blockNumber = await eth_blockNumber(rpcRequest); + const salt = options.salt + ? options.salt.startsWith("0x") && options.salt.length === 66 + ? (options.salt as `0x${string}`) + : keccakId(options.salt) + : toHex(blockNumber, { + size: 32, + }); + + const entrypoint = await getOrDeployEntrypointERC20(options); + + let hookData: Hex = "0x"; + let amount = toUnits( + params.maxSupply.toString() || DEFAULT_MAX_SUPPLY_ERC20.toString(), + 18, + ); + if (launchConfig?.kind === "pool") { + hookData = encodePoolConfig(launchConfig.config); + amount = toUnits( + launchConfig.config.amount.toString() || + DEFAULT_MAX_SUPPLY_ERC20.toString(), + 18, + ); + } else if (launchConfig?.kind === "market") { + const currencyContract = + launchConfig.config.tokenOut && + launchConfig.config.tokenOut !== NATIVE_TOKEN_ADDRESS + ? getContract({ + address: launchConfig.config.tokenOut, + chain, + client, + }) + : null; + const currencyDecimals = launchConfig.config.priceDenominator + ? launchConfig.config.priceDenominator + : currencyContract + ? await decimals({ + contract: currencyContract, + }) + : 18; + + hookData = encodeMarketConfig({ + ...launchConfig.config, + decimals: currencyDecimals, + }); + } + + const transaction = createAsset({ + contract: entrypoint, + createParams: { + amount, + data: encodedInitData, + hookData, + referrer: ZERO_ADDRESS, + salt, + }, + creator, + }); + + const receipt = await sendAndConfirmTransaction({ account, transaction }); + const assetEvent = assetCreatedEvent(); + const decodedEvent = parseEventLogs({ + events: [assetEvent], + logs: receipt.logs, + }); + + if (decodedEvent.length === 0 || !decodedEvent[0]) { + throw new Error( + `No AssetCreated event found in transaction: ${receipt.transactionHash}`, + ); + } + + return decodedEvent[0]?.args.asset; +} diff --git a/packages/thirdweb/src/assets/deploy-infra-proxy.ts b/packages/thirdweb/src/assets/deploy-infra-proxy.ts new file mode 100644 index 00000000000..cc18a36ac3d --- /dev/null +++ b/packages/thirdweb/src/assets/deploy-infra-proxy.ts @@ -0,0 +1,44 @@ +import type { Hex } from "viem"; +import type { ThirdwebContract } from "../contract/contract.js"; +import { parseEventLogs } from "../event/actions/parse-logs.js"; +import { assetInfraDeployedEvent } from "../extensions/assets/__generated__/AssetInfraDeployer/events/AssetInfraDeployed.js"; +import { deployInfraProxyDeterministic } from "../extensions/assets/__generated__/AssetInfraDeployer/write/deployInfraProxyDeterministic.js"; +import { sendAndConfirmTransaction } from "../transaction/actions/send-and-confirm-transaction.js"; +import { keccakId } from "../utils/any-evm/keccak-id.js"; +import type { ClientAndChainAndAccount } from "../utils/types.js"; +import { DEFAULT_SALT } from "./constants.js"; + +export async function deployInfraProxy( + options: ClientAndChainAndAccount & { + assetFactory: ThirdwebContract; + implementationAddress: string; + initData: Hex; + extraData: Hex; + }, +) { + const transaction = deployInfraProxyDeterministic({ + contract: options.assetFactory, + data: options.initData, + extraData: options.extraData, + implementation: options.implementationAddress, + salt: keccakId(DEFAULT_SALT), + }); + + const receipt = await sendAndConfirmTransaction({ + account: options.account, + transaction, + }); + const proxyEvent = assetInfraDeployedEvent(); + const decodedEvent = parseEventLogs({ + events: [proxyEvent], + logs: receipt.logs, + }); + + if (decodedEvent.length === 0 || !decodedEvent[0]) { + throw new Error( + `No AssetInfraDeployed event found in transaction: ${receipt.transactionHash}`, + ); + } + + return decodedEvent[0]?.args.proxy; +} diff --git a/packages/thirdweb/src/assets/distribute-token.test.ts b/packages/thirdweb/src/assets/distribute-token.test.ts new file mode 100644 index 00000000000..322f39478e0 --- /dev/null +++ b/packages/thirdweb/src/assets/distribute-token.test.ts @@ -0,0 +1,116 @@ +import { getContract, type ThirdwebContract } from "src/contract/contract.js"; +import { getBalance } from "src/extensions/erc20/read/getBalance.js"; +import { approve } from "src/extensions/erc20/write/approve.js"; +import { sendAndConfirmTransaction } from "src/transaction/actions/send-and-confirm-transaction.js"; +import { toUnits } from "src/utils/units.js"; +import { beforeAll, describe, expect, it } from "vitest"; +import { ANVIL_CHAIN } from "../../test/src/chains.js"; +import { TEST_CLIENT } from "../../test/src/test-clients.js"; +import { + TEST_ACCOUNT_A, + TEST_ACCOUNT_B, + TEST_ACCOUNT_C, + TEST_ACCOUNT_D, +} from "../../test/src/test-wallets.js"; +import { createTokenByImplConfig } from "./create-token-by-impl-config.js"; +import { distributeToken } from "./distribute-token.js"; +import { getDeployedEntrypointERC20 } from "./get-entrypoint-erc20.js"; + +describe.runIf(process.env.TW_SECRET_KEY)( + "create token by impl config", + { + timeout: 20000, + }, + () => { + let token: ThirdwebContract; + beforeAll(async () => { + // create token + const tokenAddress = await createTokenByImplConfig({ + account: TEST_ACCOUNT_A, + chain: ANVIL_CHAIN, + client: TEST_CLIENT, + params: { + maxSupply: 10_000_000_000n, + name: "Test", + }, + salt: "salt123", + }); + + token = getContract({ + address: tokenAddress, + chain: ANVIL_CHAIN, + client: TEST_CLIENT, + }); + + // approve tokens to entrypoint for distribution + const entrypoint = await getDeployedEntrypointERC20({ + chain: ANVIL_CHAIN, + client: TEST_CLIENT, + }); + + const approvalTx = approve({ + amountWei: toUnits("1000", 18), + contract: token, + spender: entrypoint?.address as string, + }); + await sendAndConfirmTransaction({ + account: TEST_ACCOUNT_A, + transaction: approvalTx, + }); + }, 20000); + + it("should distrbute tokens to specified recipients", async () => { + const contents = [ + { amount: 10n, recipient: TEST_ACCOUNT_B.address }, + { amount: 15n, recipient: TEST_ACCOUNT_C.address }, + { amount: 20n, recipient: TEST_ACCOUNT_D.address }, + ]; + + const transaction = await distributeToken({ + chain: ANVIL_CHAIN, + client: TEST_CLIENT, + contents, + tokenAddress: token.address, + }); + + await sendAndConfirmTransaction({ account: TEST_ACCOUNT_A, transaction }); + + const balanceB = ( + await getBalance({ + address: TEST_ACCOUNT_B.address, + contract: token, + }) + ).value; + + const balanceC = ( + await getBalance({ + address: TEST_ACCOUNT_C.address, + contract: token, + }) + ).value; + + const balanceD = ( + await getBalance({ + address: TEST_ACCOUNT_D.address, + contract: token, + }) + ).value; + + // admin balance + const balanceA = ( + await getBalance({ + address: TEST_ACCOUNT_A.address, + contract: token, + }) + ).value; + + expect(balanceB).to.equal(toUnits("10", 18)); + expect(balanceC).to.equal(toUnits("15", 18)); + expect(balanceD).to.equal(toUnits("20", 18)); + + expect(balanceA).to.equal( + toUnits("10000000000", 18) - balanceB - balanceC - balanceD, + ); + }); + }, +); diff --git a/packages/thirdweb/src/assets/distribute-token.ts b/packages/thirdweb/src/assets/distribute-token.ts new file mode 100644 index 00000000000..6fd25acd6da --- /dev/null +++ b/packages/thirdweb/src/assets/distribute-token.ts @@ -0,0 +1,26 @@ +import { distributeAsset } from "../extensions/assets/__generated__/AssetEntrypointERC20/write/distributeAsset.js"; +import type { ClientAndChain } from "../utils/types.js"; +import { toUnits } from "../utils/units.js"; +import { getDeployedEntrypointERC20 } from "./get-entrypoint-erc20.js"; +import type { DistributeContent } from "./types.js"; + +type DistrbuteTokenParams = ClientAndChain & { + tokenAddress: string; + contents: DistributeContent[]; +}; + +export async function distributeToken(options: DistrbuteTokenParams) { + const entrypoint = await getDeployedEntrypointERC20(options); + + if (!entrypoint) { + throw new Error(`Entrypoint not found on chain: ${options.chain.id}`); + } + + return distributeAsset({ + asset: options.tokenAddress, + contents: options.contents.map((a) => { + return { ...a, amount: toUnits(a.amount.toString(), 18) }; + }), + contract: entrypoint, + }); +} diff --git a/packages/thirdweb/src/assets/get-entrypoint-erc20.ts b/packages/thirdweb/src/assets/get-entrypoint-erc20.ts new file mode 100644 index 00000000000..4d02c7789fa --- /dev/null +++ b/packages/thirdweb/src/assets/get-entrypoint-erc20.ts @@ -0,0 +1,123 @@ +import { encodePacked } from "viem"; +import { ZERO_ADDRESS } from "../constants/addresses.js"; +import { getContract, type ThirdwebContract } from "../contract/contract.js"; +import { getOrDeployInfraContract } from "../contract/deployment/utils/bootstrap.js"; +import { getDeployedInfraContract } from "../contract/deployment/utils/infra.js"; +import { encodeInitialize } from "../extensions/assets/__generated__/AssetEntrypointERC20/write/initialize.js"; +import { keccakId } from "../utils/any-evm/keccak-id.js"; +import { isContractDeployed } from "../utils/bytecode/is-contract-deployed.js"; +import { keccak256 } from "../utils/hashing/keccak256.js"; +import type { + ClientAndChain, + ClientAndChainAndAccount, +} from "../utils/types.js"; +import { deployAssetFactory, getDeployedAssetFactory } from "./bootstrap.js"; +import { + DEFAULT_INFRA_ADMIN, + DEFAULT_SALT, + IMPLEMENTATIONS, +} from "./constants.js"; +import { deployInfraProxy } from "./deploy-infra-proxy.js"; +import { getInitCodeHashERC1967 } from "./get-initcode-hash-1967.js"; + +export async function getOrDeployEntrypointERC20( + options: ClientAndChainAndAccount, +): Promise { + const implementations = IMPLEMENTATIONS[options.chain.id]; + + if (implementations?.AssetEntrypointERC20) { + return getContract({ + address: implementations.AssetEntrypointERC20, + chain: options.chain, + client: options.client, + }); + } + + let assetFactory = await getDeployedAssetFactory(options); + if (!assetFactory) { + assetFactory = await deployAssetFactory(options); + } + + const entrypointImpl = await getOrDeployInfraContract({ + ...options, + contractId: "AssetEntrypointERC20", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + version: "0.0.2", + }); + + // encode init data + const initData = encodeInitialize({ + owner: DEFAULT_INFRA_ADMIN, + rewardLocker: ZERO_ADDRESS, + router: ZERO_ADDRESS, + }); + + const entyrpointProxyAddress = await deployInfraProxy({ + ...options, + assetFactory, + extraData: "0x", + implementationAddress: entrypointImpl.address, + initData, + }); + + return getContract({ + address: entyrpointProxyAddress, + chain: options.chain, + client: options.client, + }); +} + +export async function getDeployedEntrypointERC20(options: ClientAndChain) { + const implementations = IMPLEMENTATIONS[options.chain.id]; + + if (implementations?.AssetEntrypointERC20) { + return getContract({ + address: implementations.AssetEntrypointERC20, + chain: options.chain, + client: options.client, + }); + } + + const [assetFactory, entrypointImpl] = await Promise.all([ + getDeployedAssetFactory(options), + getDeployedInfraContract({ + ...options, + contractId: "AssetEntrypointERC20", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + version: "0.0.2", + }), + ]); + + if (!assetFactory || !entrypointImpl) { + return null; + } + + const initCodeHash = getInitCodeHashERC1967(entrypointImpl.address); + + const saltHash = keccak256( + encodePacked( + ["bytes32", "address"], + [keccakId(DEFAULT_SALT), DEFAULT_INFRA_ADMIN], + ), + ); + + const hashedDeployInfo = keccak256( + encodePacked( + ["bytes1", "address", "bytes32", "bytes32"], + ["0xff", assetFactory.address, saltHash, initCodeHash], + ), + ); + + const entrypointProxyAddress = `0x${hashedDeployInfo.slice(26)}`; + const entrypointProxy = getContract({ + address: entrypointProxyAddress, + chain: options.chain, + client: options.client, + }); + + if (!(await isContractDeployed(entrypointProxy))) { + return null; + } + + return entrypointProxy; +} diff --git a/packages/thirdweb/src/assets/get-erc20-asset-impl.ts b/packages/thirdweb/src/assets/get-erc20-asset-impl.ts new file mode 100644 index 00000000000..a01d410b08e --- /dev/null +++ b/packages/thirdweb/src/assets/get-erc20-asset-impl.ts @@ -0,0 +1,24 @@ +import { getContract, type ThirdwebContract } from "../contract/contract.js"; +import { getOrDeployInfraContract } from "../contract/deployment/utils/bootstrap.js"; +import type { ClientAndChainAndAccount } from "../utils/types.js"; +import { IMPLEMENTATIONS } from "./constants.js"; + +export async function getOrDeployERC20AssetImpl( + options: ClientAndChainAndAccount, +): Promise { + const implementations = IMPLEMENTATIONS[options.chain.id]; + + if (implementations?.ERC20AssetImpl) { + return getContract({ + address: implementations.ERC20AssetImpl, + chain: options.chain, + client: options.client, + }); + } + + return await getOrDeployInfraContract({ + ...options, + contractId: "ERC20Asset", + publisher: "0x6453a486d52e0EB6E79Ec4491038E2522a926936", + }); +} diff --git a/packages/thirdweb/src/assets/get-initcode-hash-1967.ts b/packages/thirdweb/src/assets/get-initcode-hash-1967.ts new file mode 100644 index 00000000000..d1b3bd3e50a --- /dev/null +++ b/packages/thirdweb/src/assets/get-initcode-hash-1967.ts @@ -0,0 +1,8 @@ +import { keccak256 } from "../utils/hashing/keccak256.js"; + +export function getInitCodeHashERC1967(implementation: string) { + // See `initCodeHashERC1967` - LibClone {https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol} + return keccak256( + `0x603d3d8160223d3973${implementation.toLowerCase().replace(/^0x/, "")}60095155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3`, + ); +} diff --git a/packages/thirdweb/src/assets/is-router-enabled.ts b/packages/thirdweb/src/assets/is-router-enabled.ts new file mode 100644 index 00000000000..9b23d0f1d2d --- /dev/null +++ b/packages/thirdweb/src/assets/is-router-enabled.ts @@ -0,0 +1,20 @@ +import { ZERO_ADDRESS } from "../constants/addresses.js"; +import { getRouter } from "../extensions/assets/__generated__/AssetEntrypointERC20/read/getRouter.js"; +import type { ClientAndChain } from "../utils/types.js"; +import { getDeployedEntrypointERC20 } from "./get-entrypoint-erc20.js"; + +export async function isRouterEnabled( + options: ClientAndChain, +): Promise { + const entrypoint = await getDeployedEntrypointERC20(options); + + if (!entrypoint) { + return false; + } + + const router = await getRouter({ + contract: entrypoint, + }); + + return router !== ZERO_ADDRESS; +} diff --git a/packages/thirdweb/src/assets/token-utils.ts b/packages/thirdweb/src/assets/token-utils.ts new file mode 100644 index 00000000000..f9462691b2e --- /dev/null +++ b/packages/thirdweb/src/assets/token-utils.ts @@ -0,0 +1,122 @@ +import type { Hex } from "viem"; +import type { ThirdwebClient } from "../client/client.js"; +import { NATIVE_TOKEN_ADDRESS, ZERO_ADDRESS } from "../constants/addresses.js"; +import { encodeInitialize } from "../extensions/assets/__generated__/ERC20Asset/write/initialize.js"; +import { upload } from "../storage/upload.js"; +import { encodeAbiParameters } from "../utils/abi/encodeAbiParameters.js"; +import { toUnits } from "../utils/units.js"; +import { + DEFAULT_MAX_SUPPLY_ERC20, + DEFAULT_POOL_FEE, + DEFAULT_POOL_INITIAL_TICK, +} from "./constants.js"; +import type { MarketConfig, PoolConfig, TokenParams } from "./types.js"; + +export async function encodeInitParams(options: { + client: ThirdwebClient; + params: TokenParams; + creator: string; +}): Promise { + const { client, params, creator } = options; + + const contractURI = + options.params.contractURI || + (await upload({ + client, + files: [ + { + description: params.description, + external_link: params.external_link, + image: params.image, + name: params.name, + social_urls: params.social_urls, + symbol: params.symbol, + }, + ], + })) || + ""; + + return encodeInitialize({ + contractURI, + maxSupply: toUnits( + params.maxSupply.toString() || DEFAULT_MAX_SUPPLY_ERC20.toString(), + 18, + ), + name: params.name, + owner: creator, + symbol: params.symbol || params.name, + }); +} + +export function encodePoolConfig(poolConfig: PoolConfig): Hex { + const POOL_PARAMS = [ + { + name: "currency", + type: "address", + }, + { + name: "amount", + type: "uint256", + }, + { + name: "fee", + type: "uint24", + }, + { + name: "initialTick", + type: "uint24", + }, + ] as const; + + return encodeAbiParameters(POOL_PARAMS, [ + poolConfig.currency || NATIVE_TOKEN_ADDRESS, + toUnits(poolConfig.amount.toString(), 18), + poolConfig.fee || DEFAULT_POOL_FEE, + poolConfig.initialTick || DEFAULT_POOL_INITIAL_TICK, + ]); +} + +export function encodeMarketConfig( + marketConfig: MarketConfig & { decimals: number }, +): Hex { + const MARKET_PARAMS = [ + { + name: "tokenOut", + type: "address", + }, + { + name: "pricePerUnit", + type: "uint256", + }, + { + name: "priceDenominator", + type: "uint8", + }, + { + name: "startTime", + type: "uint48", + }, + { + name: "endTime", + type: "uint48", + }, + { + name: "hook", + type: "address", + }, + { + name: "hookInit", + type: "bytes", + }, + ] as const; + + return encodeAbiParameters(MARKET_PARAMS, [ + marketConfig.tokenOut || NATIVE_TOKEN_ADDRESS, + marketConfig.pricePerUnit, + marketConfig.priceDenominator || marketConfig.decimals || 18, + marketConfig.startTime || 0, + marketConfig.endTime || 0, + ZERO_ADDRESS, + "0x", + ]); +} diff --git a/packages/thirdweb/src/assets/types.ts b/packages/thirdweb/src/assets/types.ts new file mode 100644 index 00000000000..48766dff719 --- /dev/null +++ b/packages/thirdweb/src/assets/types.ts @@ -0,0 +1,51 @@ +import type { FileOrBufferOrString } from "../storage/upload/types.js"; +import type { ClientAndChainAndAccount } from "../utils/types.js"; + +export type TokenParams = { + name: string; + description?: string; + image?: FileOrBufferOrString; + external_link?: string; + social_urls?: Record; + symbol?: string; + contractURI?: string; + maxSupply: bigint; + owner?: string; +}; + +export type PoolConfig = { + amount: bigint; + currency?: string; + fee?: number; + initialTick?: number; +}; + +export type MarketConfig = { + tokenOut?: string; + pricePerUnit: bigint; + priceDenominator?: number; + startTime?: number; + endTime?: number; + hookAddress?: string; + hookInitData?: string; +}; + +export type DistributeContent = { + amount: bigint; + recipient: string; +}; + +type DistributeConfig = { + content: DistributeContent[]; +}; + +type LaunchConfig = + | { kind: "pool"; config: PoolConfig } + | { kind: "market"; config: MarketConfig } + | { kind: "distribute"; config: DistributeConfig }; + +export type CreateTokenOptions = ClientAndChainAndAccount & { + salt?: string; + params: TokenParams; + launchConfig?: LaunchConfig; +}; diff --git a/packages/thirdweb/src/exports/assets.ts b/packages/thirdweb/src/exports/assets.ts new file mode 100644 index 00000000000..17163b74355 --- /dev/null +++ b/packages/thirdweb/src/exports/assets.ts @@ -0,0 +1,22 @@ +export { + deployAssetFactory, + deployFeeManager, + deployRewardLocker, + deployRouter, + getDeployedAssetFactory, + getDeployedFeeManager, + getDeployedRewardLocker, + getDeployedRouter, +} from "../assets/bootstrap.js"; +export { createToken } from "../assets/create-token.js"; +export { createTokenByImplConfig } from "../assets/create-token-by-impl-config.js"; +export { distributeToken } from "../assets/distribute-token.js"; +export { getDeployedEntrypointERC20 } from "../assets/get-entrypoint-erc20.js"; +export { isRouterEnabled } from "../assets/is-router-enabled.js"; +export type { + CreateTokenOptions, + DistributeContent, + MarketConfig, + PoolConfig, + TokenParams, +} from "../assets/types.js"; diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/AssetCreated.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/AssetCreated.ts new file mode 100644 index 00000000000..95291f68765 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/AssetCreated.ts @@ -0,0 +1,47 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareEvent } from "../../../../../event/prepare-event.js"; + +/** + * Represents the filters for the "AssetCreated" event. + */ +export type AssetCreatedEventFilters = Partial<{ + creator: AbiParameterToPrimitiveType<{ + type: "address"; + name: "creator"; + indexed: true; + }>; + asset: AbiParameterToPrimitiveType<{ + type: "address"; + name: "asset"; + indexed: true; + }>; +}>; + +/** + * Creates an event object for the AssetCreated event. + * @param filters - Optional filters to apply to the event. + * @returns The prepared event object. + * @extension ASSETS + * @example + * ```ts + * import { getContractEvents } from "thirdweb"; + * import { assetCreatedEvent } from "thirdweb/extensions/assets"; + * + * const events = await getContractEvents({ + * contract, + * events: [ + * assetCreatedEvent({ + * creator: ..., + * asset: ..., + * }) + * ], + * }); + * ``` + */ +export function assetCreatedEvent(filters: AssetCreatedEventFilters = {}) { + return prepareEvent({ + filters, + signature: + "event AssetCreated(bytes32 contractId, address indexed creator, address indexed asset, address referrer, bytes aux)", + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/AssetDistributed.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/AssetDistributed.ts new file mode 100644 index 00000000000..6367047c30b --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/AssetDistributed.ts @@ -0,0 +1,25 @@ +import { prepareEvent } from "../../../../../event/prepare-event.js"; + +/** + * Creates an event object for the AssetDistributed event. + * @returns The prepared event object. + * @extension ASSETS + * @example + * ```ts + * import { getContractEvents } from "thirdweb"; + * import { assetDistributedEvent } from "thirdweb/extensions/assets"; + * + * const events = await getContractEvents({ + * contract, + * events: [ + * assetDistributedEvent() + * ], + * }); + * ``` + */ +export function assetDistributedEvent() { + return prepareEvent({ + signature: + "event AssetDistributed(address asset, uint256 recipientCount, uint256 totalAmount)", + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/ImplementationAdded.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/ImplementationAdded.ts new file mode 100644 index 00000000000..81b10e03836 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/ImplementationAdded.ts @@ -0,0 +1,43 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareEvent } from "../../../../../event/prepare-event.js"; + +/** + * Represents the filters for the "ImplementationAdded" event. + */ +export type ImplementationAddedEventFilters = Partial<{ + implementation: AbiParameterToPrimitiveType<{ + type: "address"; + name: "implementation"; + indexed: true; + }>; +}>; + +/** + * Creates an event object for the ImplementationAdded event. + * @param filters - Optional filters to apply to the event. + * @returns The prepared event object. + * @extension ASSETS + * @example + * ```ts + * import { getContractEvents } from "thirdweb"; + * import { implementationAddedEvent } from "thirdweb/extensions/assets"; + * + * const events = await getContractEvents({ + * contract, + * events: [ + * implementationAddedEvent({ + * implementation: ..., + * }) + * ], + * }); + * ``` + */ +export function implementationAddedEvent( + filters: ImplementationAddedEventFilters = {}, +) { + return prepareEvent({ + filters, + signature: + "event ImplementationAdded(bytes32 contractId, address indexed implementation, uint8 implementationType, uint8 createHook, bytes32 createHookData)", + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/RewardLockerUpdated.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/RewardLockerUpdated.ts new file mode 100644 index 00000000000..23e56bb89a9 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/RewardLockerUpdated.ts @@ -0,0 +1,42 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareEvent } from "../../../../../event/prepare-event.js"; + +/** + * Represents the filters for the "RewardLockerUpdated" event. + */ +export type RewardLockerUpdatedEventFilters = Partial<{ + locker: AbiParameterToPrimitiveType<{ + type: "address"; + name: "locker"; + indexed: true; + }>; +}>; + +/** + * Creates an event object for the RewardLockerUpdated event. + * @param filters - Optional filters to apply to the event. + * @returns The prepared event object. + * @extension ASSETS + * @example + * ```ts + * import { getContractEvents } from "thirdweb"; + * import { rewardLockerUpdatedEvent } from "thirdweb/extensions/assets"; + * + * const events = await getContractEvents({ + * contract, + * events: [ + * rewardLockerUpdatedEvent({ + * locker: ..., + * }) + * ], + * }); + * ``` + */ +export function rewardLockerUpdatedEvent( + filters: RewardLockerUpdatedEventFilters = {}, +) { + return prepareEvent({ + filters, + signature: "event RewardLockerUpdated(address indexed locker)", + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/RouterUpdated.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/RouterUpdated.ts new file mode 100644 index 00000000000..c2fa8133d8c --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/events/RouterUpdated.ts @@ -0,0 +1,40 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareEvent } from "../../../../../event/prepare-event.js"; + +/** + * Represents the filters for the "RouterUpdated" event. + */ +export type RouterUpdatedEventFilters = Partial<{ + router: AbiParameterToPrimitiveType<{ + type: "address"; + name: "router"; + indexed: true; + }>; +}>; + +/** + * Creates an event object for the RouterUpdated event. + * @param filters - Optional filters to apply to the event. + * @returns The prepared event object. + * @extension ASSETS + * @example + * ```ts + * import { getContractEvents } from "thirdweb"; + * import { routerUpdatedEvent } from "thirdweb/extensions/assets"; + * + * const events = await getContractEvents({ + * contract, + * events: [ + * routerUpdatedEvent({ + * router: ..., + * }) + * ], + * }); + * ``` + */ +export function routerUpdatedEvent(filters: RouterUpdatedEventFilters = {}) { + return prepareEvent({ + filters, + signature: "event RouterUpdated(address indexed router)", + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/read/getImplementation.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/read/getImplementation.ts new file mode 100644 index 00000000000..61f2a869cb3 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/read/getImplementation.ts @@ -0,0 +1,152 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { decodeAbiParameters } from "viem"; +import { readContract } from "../../../../../transaction/read-contract.js"; +import type { BaseTransactionOptions } from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import type { Hex } from "../../../../../utils/encoding/hex.js"; + +/** + * Represents the parameters for the "getImplementation" function. + */ +export type GetImplementationParams = { + contractId: AbiParameterToPrimitiveType<{ + type: "bytes32"; + name: "contractId"; + }>; +}; + +export const FN_SELECTOR = "0x3c2e0828" as const; +const FN_INPUTS = [ + { + name: "contractId", + type: "bytes32", + }, +] as const; +const FN_OUTPUTS = [ + { + components: [ + { + name: "contractId", + type: "bytes32", + }, + { + name: "implementation", + type: "address", + }, + { + name: "implementationType", + type: "uint8", + }, + { + name: "createHook", + type: "uint8", + }, + { + name: "createHookData", + type: "bytes", + }, + ], + type: "tuple", + }, +] as const; + +/** + * Checks if the `getImplementation` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `getImplementation` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isGetImplementationSupported } from "thirdweb/extensions/assets"; + * const supported = isGetImplementationSupported(["0x..."]); + * ``` + */ +export function isGetImplementationSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "getImplementation" function. + * @param options - The options for the getImplementation function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeGetImplementationParams } from "thirdweb/extensions/assets"; + * const result = encodeGetImplementationParams({ + * contractId: ..., + * }); + * ``` + */ +export function encodeGetImplementationParams( + options: GetImplementationParams, +) { + return encodeAbiParameters(FN_INPUTS, [options.contractId]); +} + +/** + * Encodes the "getImplementation" function into a Hex string with its parameters. + * @param options - The options for the getImplementation function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeGetImplementation } from "thirdweb/extensions/assets"; + * const result = encodeGetImplementation({ + * contractId: ..., + * }); + * ``` + */ +export function encodeGetImplementation(options: GetImplementationParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeGetImplementationParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Decodes the result of the getImplementation function call. + * @param result - The hexadecimal result to decode. + * @returns The decoded result as per the FN_OUTPUTS definition. + * @extension ASSETS + * @example + * ```ts + * import { decodeGetImplementationResult } from "thirdweb/extensions/assets"; + * const result = decodeGetImplementationResultResult("..."); + * ``` + */ +export function decodeGetImplementationResult(result: Hex) { + return decodeAbiParameters(FN_OUTPUTS, result)[0]; +} + +/** + * Calls the "getImplementation" function on the contract. + * @param options - The options for the getImplementation function. + * @returns The parsed result of the function call. + * @extension ASSETS + * @example + * ```ts + * import { getImplementation } from "thirdweb/extensions/assets"; + * + * const result = await getImplementation({ + * contract, + * contractId: ..., + * }); + * + * ``` + */ +export async function getImplementation( + options: BaseTransactionOptions, +) { + return readContract({ + contract: options.contract, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + params: [options.contractId], + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/read/getRewardLocker.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/read/getRewardLocker.ts new file mode 100644 index 00000000000..37080c9174b --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/read/getRewardLocker.ts @@ -0,0 +1,70 @@ +import { decodeAbiParameters } from "viem"; +import { readContract } from "../../../../../transaction/read-contract.js"; +import type { BaseTransactionOptions } from "../../../../../transaction/types.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import type { Hex } from "../../../../../utils/encoding/hex.js"; + +export const FN_SELECTOR = "0xb0188df2" as const; +const FN_INPUTS = [] as const; +const FN_OUTPUTS = [ + { + name: "rewardLocker", + type: "address", + }, +] as const; + +/** + * Checks if the `getRewardLocker` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `getRewardLocker` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isGetRewardLockerSupported } from "thirdweb/extensions/assets"; + * const supported = isGetRewardLockerSupported(["0x..."]); + * ``` + */ +export function isGetRewardLockerSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Decodes the result of the getRewardLocker function call. + * @param result - The hexadecimal result to decode. + * @returns The decoded result as per the FN_OUTPUTS definition. + * @extension ASSETS + * @example + * ```ts + * import { decodeGetRewardLockerResult } from "thirdweb/extensions/assets"; + * const result = decodeGetRewardLockerResultResult("..."); + * ``` + */ +export function decodeGetRewardLockerResult(result: Hex) { + return decodeAbiParameters(FN_OUTPUTS, result)[0]; +} + +/** + * Calls the "getRewardLocker" function on the contract. + * @param options - The options for the getRewardLocker function. + * @returns The parsed result of the function call. + * @extension ASSETS + * @example + * ```ts + * import { getRewardLocker } from "thirdweb/extensions/assets"; + * + * const result = await getRewardLocker({ + * contract, + * }); + * + * ``` + */ +export async function getRewardLocker(options: BaseTransactionOptions) { + return readContract({ + contract: options.contract, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + params: [], + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/read/getRouter.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/read/getRouter.ts new file mode 100644 index 00000000000..a1498baac8a --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/read/getRouter.ts @@ -0,0 +1,70 @@ +import { decodeAbiParameters } from "viem"; +import { readContract } from "../../../../../transaction/read-contract.js"; +import type { BaseTransactionOptions } from "../../../../../transaction/types.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import type { Hex } from "../../../../../utils/encoding/hex.js"; + +export const FN_SELECTOR = "0xb0f479a1" as const; +const FN_INPUTS = [] as const; +const FN_OUTPUTS = [ + { + name: "router", + type: "address", + }, +] as const; + +/** + * Checks if the `getRouter` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `getRouter` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isGetRouterSupported } from "thirdweb/extensions/assets"; + * const supported = isGetRouterSupported(["0x..."]); + * ``` + */ +export function isGetRouterSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Decodes the result of the getRouter function call. + * @param result - The hexadecimal result to decode. + * @returns The decoded result as per the FN_OUTPUTS definition. + * @extension ASSETS + * @example + * ```ts + * import { decodeGetRouterResult } from "thirdweb/extensions/assets"; + * const result = decodeGetRouterResultResult("..."); + * ``` + */ +export function decodeGetRouterResult(result: Hex) { + return decodeAbiParameters(FN_OUTPUTS, result)[0]; +} + +/** + * Calls the "getRouter" function on the contract. + * @param options - The options for the getRouter function. + * @returns The parsed result of the function call. + * @extension ASSETS + * @example + * ```ts + * import { getRouter } from "thirdweb/extensions/assets"; + * + * const result = await getRouter({ + * contract, + * }); + * + * ``` + */ +export async function getRouter(options: BaseTransactionOptions) { + return readContract({ + contract: options.contract, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + params: [], + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/addImplementation.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/addImplementation.ts new file mode 100644 index 00000000000..8d158c238a2 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/addImplementation.ts @@ -0,0 +1,181 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "addImplementation" function. + */ +export type AddImplementationParams = WithOverrides<{ + config: AbiParameterToPrimitiveType<{ + type: "tuple"; + name: "config"; + components: [ + { type: "bytes32"; name: "contractId" }, + { type: "address"; name: "implementation" }, + { type: "uint8"; name: "implementationType" }, + { type: "uint8"; name: "createHook" }, + { type: "bytes"; name: "createHookData" }, + ]; + }>; + isDefault: AbiParameterToPrimitiveType<{ type: "bool"; name: "isDefault" }>; +}>; + +export const FN_SELECTOR = "0x4bf8055d" as const; +const FN_INPUTS = [ + { + components: [ + { + name: "contractId", + type: "bytes32", + }, + { + name: "implementation", + type: "address", + }, + { + name: "implementationType", + type: "uint8", + }, + { + name: "createHook", + type: "uint8", + }, + { + name: "createHookData", + type: "bytes", + }, + ], + name: "config", + type: "tuple", + }, + { + name: "isDefault", + type: "bool", + }, +] as const; +const FN_OUTPUTS = [] as const; + +/** + * Checks if the `addImplementation` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `addImplementation` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isAddImplementationSupported } from "thirdweb/extensions/assets"; + * + * const supported = isAddImplementationSupported(["0x..."]); + * ``` + */ +export function isAddImplementationSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "addImplementation" function. + * @param options - The options for the addImplementation function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeAddImplementationParams } from "thirdweb/extensions/assets"; + * const result = encodeAddImplementationParams({ + * config: ..., + * isDefault: ..., + * }); + * ``` + */ +export function encodeAddImplementationParams( + options: AddImplementationParams, +) { + return encodeAbiParameters(FN_INPUTS, [options.config, options.isDefault]); +} + +/** + * Encodes the "addImplementation" function into a Hex string with its parameters. + * @param options - The options for the addImplementation function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeAddImplementation } from "thirdweb/extensions/assets"; + * const result = encodeAddImplementation({ + * config: ..., + * isDefault: ..., + * }); + * ``` + */ +export function encodeAddImplementation(options: AddImplementationParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeAddImplementationParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "addImplementation" function on the contract. + * @param options - The options for the "addImplementation" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { addImplementation } from "thirdweb/extensions/assets"; + * + * const transaction = addImplementation({ + * contract, + * config: ..., + * isDefault: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function addImplementation( + options: BaseTransactionOptions< + | AddImplementationParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [resolvedOptions.config, resolvedOptions.isDefault] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/buyAsset.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/buyAsset.ts new file mode 100644 index 00000000000..8dec5f4df9b --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/buyAsset.ts @@ -0,0 +1,196 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "buyAsset" function. + */ +export type BuyAssetParams = WithOverrides<{ + asset: AbiParameterToPrimitiveType<{ type: "address"; name: "asset" }>; + params: AbiParameterToPrimitiveType<{ + type: "tuple"; + name: "params"; + components: [ + { type: "address"; name: "recipient" }, + { type: "address"; name: "referrer" }, + { type: "address"; name: "tokenIn" }, + { type: "uint256"; name: "amountIn" }, + { type: "uint256"; name: "minAmountOut" }, + { type: "uint256"; name: "deadline" }, + { type: "bytes"; name: "data" }, + ]; + }>; +}>; + +export const FN_SELECTOR = "0x4af11f67" as const; +const FN_INPUTS = [ + { + name: "asset", + type: "address", + }, + { + components: [ + { + name: "recipient", + type: "address", + }, + { + name: "referrer", + type: "address", + }, + { + name: "tokenIn", + type: "address", + }, + { + name: "amountIn", + type: "uint256", + }, + { + name: "minAmountOut", + type: "uint256", + }, + { + name: "deadline", + type: "uint256", + }, + { + name: "data", + type: "bytes", + }, + ], + name: "params", + type: "tuple", + }, +] as const; +const FN_OUTPUTS = [ + { + name: "amountIn", + type: "uint256", + }, + { + name: "amountOut", + type: "uint256", + }, +] as const; + +/** + * Checks if the `buyAsset` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `buyAsset` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isBuyAssetSupported } from "thirdweb/extensions/assets"; + * + * const supported = isBuyAssetSupported(["0x..."]); + * ``` + */ +export function isBuyAssetSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "buyAsset" function. + * @param options - The options for the buyAsset function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeBuyAssetParams } from "thirdweb/extensions/assets"; + * const result = encodeBuyAssetParams({ + * asset: ..., + * params: ..., + * }); + * ``` + */ +export function encodeBuyAssetParams(options: BuyAssetParams) { + return encodeAbiParameters(FN_INPUTS, [options.asset, options.params]); +} + +/** + * Encodes the "buyAsset" function into a Hex string with its parameters. + * @param options - The options for the buyAsset function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeBuyAsset } from "thirdweb/extensions/assets"; + * const result = encodeBuyAsset({ + * asset: ..., + * params: ..., + * }); + * ``` + */ +export function encodeBuyAsset(options: BuyAssetParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeBuyAssetParams(options).slice(2)) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "buyAsset" function on the contract. + * @param options - The options for the "buyAsset" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { buyAsset } from "thirdweb/extensions/assets"; + * + * const transaction = buyAsset({ + * contract, + * asset: ..., + * params: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function buyAsset( + options: BaseTransactionOptions< + | BuyAssetParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [resolvedOptions.asset, resolvedOptions.params] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAsset.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAsset.ts new file mode 100644 index 00000000000..cbb24740e9c --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAsset.ts @@ -0,0 +1,187 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "createAsset" function. + */ +export type CreateAssetParams = WithOverrides<{ + creator: AbiParameterToPrimitiveType<{ type: "address"; name: "creator" }>; + createParams: AbiParameterToPrimitiveType<{ + type: "tuple"; + name: "createParams"; + components: [ + { type: "uint256"; name: "amount" }, + { type: "address"; name: "referrer" }, + { type: "bytes32"; name: "salt" }, + { type: "bytes"; name: "data" }, + { type: "bytes"; name: "hookData" }, + ]; + }>; +}>; + +export const FN_SELECTOR = "0x58ac06bd" as const; +const FN_INPUTS = [ + { + name: "creator", + type: "address", + }, + { + components: [ + { + name: "amount", + type: "uint256", + }, + { + name: "referrer", + type: "address", + }, + { + name: "salt", + type: "bytes32", + }, + { + name: "data", + type: "bytes", + }, + { + name: "hookData", + type: "bytes", + }, + ], + name: "createParams", + type: "tuple", + }, +] as const; +const FN_OUTPUTS = [ + { + name: "asset", + type: "address", + }, +] as const; + +/** + * Checks if the `createAsset` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `createAsset` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isCreateAssetSupported } from "thirdweb/extensions/assets"; + * + * const supported = isCreateAssetSupported(["0x..."]); + * ``` + */ +export function isCreateAssetSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "createAsset" function. + * @param options - The options for the createAsset function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeCreateAssetParams } from "thirdweb/extensions/assets"; + * const result = encodeCreateAssetParams({ + * creator: ..., + * createParams: ..., + * }); + * ``` + */ +export function encodeCreateAssetParams(options: CreateAssetParams) { + return encodeAbiParameters(FN_INPUTS, [ + options.creator, + options.createParams, + ]); +} + +/** + * Encodes the "createAsset" function into a Hex string with its parameters. + * @param options - The options for the createAsset function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeCreateAsset } from "thirdweb/extensions/assets"; + * const result = encodeCreateAsset({ + * creator: ..., + * createParams: ..., + * }); + * ``` + */ +export function encodeCreateAsset(options: CreateAssetParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeCreateAssetParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "createAsset" function on the contract. + * @param options - The options for the "createAsset" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { createAsset } from "thirdweb/extensions/assets"; + * + * const transaction = createAsset({ + * contract, + * creator: ..., + * createParams: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function createAsset( + options: BaseTransactionOptions< + | CreateAssetParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [resolvedOptions.creator, resolvedOptions.createParams] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAssetById.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAssetById.ts new file mode 100644 index 00000000000..d3b420e1c29 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAssetById.ts @@ -0,0 +1,203 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "createAssetById" function. + */ +export type CreateAssetByIdParams = WithOverrides<{ + contractId: AbiParameterToPrimitiveType<{ + type: "bytes32"; + name: "contractId"; + }>; + creator: AbiParameterToPrimitiveType<{ type: "address"; name: "creator" }>; + params: AbiParameterToPrimitiveType<{ + type: "tuple"; + name: "params"; + components: [ + { type: "uint256"; name: "amount" }, + { type: "address"; name: "referrer" }, + { type: "bytes32"; name: "salt" }, + { type: "bytes"; name: "data" }, + { type: "bytes"; name: "hookData" }, + ]; + }>; +}>; + +export const FN_SELECTOR = "0x1c8dd10a" as const; +const FN_INPUTS = [ + { + name: "contractId", + type: "bytes32", + }, + { + name: "creator", + type: "address", + }, + { + components: [ + { + name: "amount", + type: "uint256", + }, + { + name: "referrer", + type: "address", + }, + { + name: "salt", + type: "bytes32", + }, + { + name: "data", + type: "bytes", + }, + { + name: "hookData", + type: "bytes", + }, + ], + name: "params", + type: "tuple", + }, +] as const; +const FN_OUTPUTS = [ + { + name: "asset", + type: "address", + }, +] as const; + +/** + * Checks if the `createAssetById` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `createAssetById` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isCreateAssetByIdSupported } from "thirdweb/extensions/assets"; + * + * const supported = isCreateAssetByIdSupported(["0x..."]); + * ``` + */ +export function isCreateAssetByIdSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "createAssetById" function. + * @param options - The options for the createAssetById function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeCreateAssetByIdParams } from "thirdweb/extensions/assets"; + * const result = encodeCreateAssetByIdParams({ + * contractId: ..., + * creator: ..., + * params: ..., + * }); + * ``` + */ +export function encodeCreateAssetByIdParams(options: CreateAssetByIdParams) { + return encodeAbiParameters(FN_INPUTS, [ + options.contractId, + options.creator, + options.params, + ]); +} + +/** + * Encodes the "createAssetById" function into a Hex string with its parameters. + * @param options - The options for the createAssetById function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeCreateAssetById } from "thirdweb/extensions/assets"; + * const result = encodeCreateAssetById({ + * contractId: ..., + * creator: ..., + * params: ..., + * }); + * ``` + */ +export function encodeCreateAssetById(options: CreateAssetByIdParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeCreateAssetByIdParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "createAssetById" function on the contract. + * @param options - The options for the "createAssetById" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { createAssetById } from "thirdweb/extensions/assets"; + * + * const transaction = createAssetById({ + * contract, + * contractId: ..., + * creator: ..., + * params: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function createAssetById( + options: BaseTransactionOptions< + | CreateAssetByIdParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [ + resolvedOptions.contractId, + resolvedOptions.creator, + resolvedOptions.params, + ] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAssetByImplementationConfig.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAssetByImplementationConfig.ts new file mode 100644 index 00000000000..78ae878f899 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAssetByImplementationConfig.ts @@ -0,0 +1,238 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "createAssetByImplementationConfig" function. + */ +export type CreateAssetByImplementationConfigParams = WithOverrides<{ + config: AbiParameterToPrimitiveType<{ + type: "tuple"; + name: "config"; + components: [ + { type: "bytes32"; name: "contractId" }, + { type: "address"; name: "implementation" }, + { type: "uint8"; name: "implementationType" }, + { type: "uint8"; name: "createHook" }, + { type: "bytes"; name: "createHookData" }, + ]; + }>; + creator: AbiParameterToPrimitiveType<{ type: "address"; name: "creator" }>; + params: AbiParameterToPrimitiveType<{ + type: "tuple"; + name: "params"; + components: [ + { type: "uint256"; name: "amount" }, + { type: "address"; name: "referrer" }, + { type: "bytes32"; name: "salt" }, + { type: "bytes"; name: "data" }, + { type: "bytes"; name: "hookData" }, + ]; + }>; +}>; + +export const FN_SELECTOR = "0x230ffc78" as const; +const FN_INPUTS = [ + { + components: [ + { + name: "contractId", + type: "bytes32", + }, + { + name: "implementation", + type: "address", + }, + { + name: "implementationType", + type: "uint8", + }, + { + name: "createHook", + type: "uint8", + }, + { + name: "createHookData", + type: "bytes", + }, + ], + name: "config", + type: "tuple", + }, + { + name: "creator", + type: "address", + }, + { + components: [ + { + name: "amount", + type: "uint256", + }, + { + name: "referrer", + type: "address", + }, + { + name: "salt", + type: "bytes32", + }, + { + name: "data", + type: "bytes", + }, + { + name: "hookData", + type: "bytes", + }, + ], + name: "params", + type: "tuple", + }, +] as const; +const FN_OUTPUTS = [ + { + name: "asset", + type: "address", + }, +] as const; + +/** + * Checks if the `createAssetByImplementationConfig` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `createAssetByImplementationConfig` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isCreateAssetByImplementationConfigSupported } from "thirdweb/extensions/assets"; + * + * const supported = isCreateAssetByImplementationConfigSupported(["0x..."]); + * ``` + */ +export function isCreateAssetByImplementationConfigSupported( + availableSelectors: string[], +) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "createAssetByImplementationConfig" function. + * @param options - The options for the createAssetByImplementationConfig function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeCreateAssetByImplementationConfigParams } from "thirdweb/extensions/assets"; + * const result = encodeCreateAssetByImplementationConfigParams({ + * config: ..., + * creator: ..., + * params: ..., + * }); + * ``` + */ +export function encodeCreateAssetByImplementationConfigParams( + options: CreateAssetByImplementationConfigParams, +) { + return encodeAbiParameters(FN_INPUTS, [ + options.config, + options.creator, + options.params, + ]); +} + +/** + * Encodes the "createAssetByImplementationConfig" function into a Hex string with its parameters. + * @param options - The options for the createAssetByImplementationConfig function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeCreateAssetByImplementationConfig } from "thirdweb/extensions/assets"; + * const result = encodeCreateAssetByImplementationConfig({ + * config: ..., + * creator: ..., + * params: ..., + * }); + * ``` + */ +export function encodeCreateAssetByImplementationConfig( + options: CreateAssetByImplementationConfigParams, +) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeCreateAssetByImplementationConfigParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "createAssetByImplementationConfig" function on the contract. + * @param options - The options for the "createAssetByImplementationConfig" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { createAssetByImplementationConfig } from "thirdweb/extensions/assets"; + * + * const transaction = createAssetByImplementationConfig({ + * contract, + * config: ..., + * creator: ..., + * params: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function createAssetByImplementationConfig( + options: BaseTransactionOptions< + | CreateAssetByImplementationConfigParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [ + resolvedOptions.config, + resolvedOptions.creator, + resolvedOptions.params, + ] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/distributeAsset.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/distributeAsset.ts new file mode 100644 index 00000000000..1cc7ca4390c --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/distributeAsset.ts @@ -0,0 +1,164 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "distributeAsset" function. + */ +export type DistributeAssetParams = WithOverrides<{ + asset: AbiParameterToPrimitiveType<{ type: "address"; name: "asset" }>; + contents: AbiParameterToPrimitiveType<{ + type: "tuple[]"; + name: "contents"; + components: [ + { type: "uint256"; name: "amount" }, + { type: "address"; name: "recipient" }, + ]; + }>; +}>; + +export const FN_SELECTOR = "0x5954167a" as const; +const FN_INPUTS = [ + { + name: "asset", + type: "address", + }, + { + components: [ + { + name: "amount", + type: "uint256", + }, + { + name: "recipient", + type: "address", + }, + ], + name: "contents", + type: "tuple[]", + }, +] as const; +const FN_OUTPUTS = [] as const; + +/** + * Checks if the `distributeAsset` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `distributeAsset` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isDistributeAssetSupported } from "thirdweb/extensions/assets"; + * + * const supported = isDistributeAssetSupported(["0x..."]); + * ``` + */ +export function isDistributeAssetSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "distributeAsset" function. + * @param options - The options for the distributeAsset function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeDistributeAssetParams } from "thirdweb/extensions/assets"; + * const result = encodeDistributeAssetParams({ + * asset: ..., + * contents: ..., + * }); + * ``` + */ +export function encodeDistributeAssetParams(options: DistributeAssetParams) { + return encodeAbiParameters(FN_INPUTS, [options.asset, options.contents]); +} + +/** + * Encodes the "distributeAsset" function into a Hex string with its parameters. + * @param options - The options for the distributeAsset function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeDistributeAsset } from "thirdweb/extensions/assets"; + * const result = encodeDistributeAsset({ + * asset: ..., + * contents: ..., + * }); + * ``` + */ +export function encodeDistributeAsset(options: DistributeAssetParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeDistributeAssetParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "distributeAsset" function on the contract. + * @param options - The options for the "distributeAsset" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { distributeAsset } from "thirdweb/extensions/assets"; + * + * const transaction = distributeAsset({ + * contract, + * asset: ..., + * contents: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function distributeAsset( + options: BaseTransactionOptions< + | DistributeAssetParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [resolvedOptions.asset, resolvedOptions.contents] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/initialize.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/initialize.ts new file mode 100644 index 00000000000..9b2125c2130 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/initialize.ts @@ -0,0 +1,166 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "initialize" function. + */ +export type InitializeParams = WithOverrides<{ + owner: AbiParameterToPrimitiveType<{ type: "address"; name: "_owner" }>; + router: AbiParameterToPrimitiveType<{ type: "address"; name: "_router" }>; + rewardLocker: AbiParameterToPrimitiveType<{ + type: "address"; + name: "_rewardLocker"; + }>; +}>; + +export const FN_SELECTOR = "0xc0c53b8b" as const; +const FN_INPUTS = [ + { + name: "_owner", + type: "address", + }, + { + name: "_router", + type: "address", + }, + { + name: "_rewardLocker", + type: "address", + }, +] as const; +const FN_OUTPUTS = [] as const; + +/** + * Checks if the `initialize` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `initialize` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isInitializeSupported } from "thirdweb/extensions/assets"; + * + * const supported = isInitializeSupported(["0x..."]); + * ``` + */ +export function isInitializeSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "initialize" function. + * @param options - The options for the initialize function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeInitializeParams } from "thirdweb/extensions/assets"; + * const result = encodeInitializeParams({ + * owner: ..., + * router: ..., + * rewardLocker: ..., + * }); + * ``` + */ +export function encodeInitializeParams(options: InitializeParams) { + return encodeAbiParameters(FN_INPUTS, [ + options.owner, + options.router, + options.rewardLocker, + ]); +} + +/** + * Encodes the "initialize" function into a Hex string with its parameters. + * @param options - The options for the initialize function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeInitialize } from "thirdweb/extensions/assets"; + * const result = encodeInitialize({ + * owner: ..., + * router: ..., + * rewardLocker: ..., + * }); + * ``` + */ +export function encodeInitialize(options: InitializeParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeInitializeParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "initialize" function on the contract. + * @param options - The options for the "initialize" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { initialize } from "thirdweb/extensions/assets"; + * + * const transaction = initialize({ + * contract, + * owner: ..., + * router: ..., + * rewardLocker: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function initialize( + options: BaseTransactionOptions< + | InitializeParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [ + resolvedOptions.owner, + resolvedOptions.router, + resolvedOptions.rewardLocker, + ] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/listAsset.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/listAsset.ts new file mode 100644 index 00000000000..c3f781b6a36 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/listAsset.ts @@ -0,0 +1,174 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "listAsset" function. + */ +export type ListAssetParams = WithOverrides<{ + asset: AbiParameterToPrimitiveType<{ type: "address"; name: "asset" }>; + params: AbiParameterToPrimitiveType<{ + type: "tuple"; + name: "params"; + components: [ + { type: "address"; name: "tokenIn" }, + { type: "uint256"; name: "price" }, + { type: "uint256"; name: "duration" }, + { type: "bytes"; name: "data" }, + ]; + }>; +}>; + +export const FN_SELECTOR = "0x80ac2260" as const; +const FN_INPUTS = [ + { + name: "asset", + type: "address", + }, + { + components: [ + { + name: "tokenIn", + type: "address", + }, + { + name: "price", + type: "uint256", + }, + { + name: "duration", + type: "uint256", + }, + { + name: "data", + type: "bytes", + }, + ], + name: "params", + type: "tuple", + }, +] as const; +const FN_OUTPUTS = [] as const; + +/** + * Checks if the `listAsset` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `listAsset` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isListAssetSupported } from "thirdweb/extensions/assets"; + * + * const supported = isListAssetSupported(["0x..."]); + * ``` + */ +export function isListAssetSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "listAsset" function. + * @param options - The options for the listAsset function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeListAssetParams } from "thirdweb/extensions/assets"; + * const result = encodeListAssetParams({ + * asset: ..., + * params: ..., + * }); + * ``` + */ +export function encodeListAssetParams(options: ListAssetParams) { + return encodeAbiParameters(FN_INPUTS, [options.asset, options.params]); +} + +/** + * Encodes the "listAsset" function into a Hex string with its parameters. + * @param options - The options for the listAsset function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeListAsset } from "thirdweb/extensions/assets"; + * const result = encodeListAsset({ + * asset: ..., + * params: ..., + * }); + * ``` + */ +export function encodeListAsset(options: ListAssetParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeListAssetParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "listAsset" function on the contract. + * @param options - The options for the "listAsset" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { listAsset } from "thirdweb/extensions/assets"; + * + * const transaction = listAsset({ + * contract, + * asset: ..., + * params: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function listAsset( + options: BaseTransactionOptions< + | ListAssetParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [resolvedOptions.asset, resolvedOptions.params] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/sellAsset.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/sellAsset.ts new file mode 100644 index 00000000000..c8be8f33fc2 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/sellAsset.ts @@ -0,0 +1,193 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "sellAsset" function. + */ +export type SellAssetParams = WithOverrides<{ + asset: AbiParameterToPrimitiveType<{ type: "address"; name: "asset" }>; + params: AbiParameterToPrimitiveType<{ + type: "tuple"; + name: "params"; + components: [ + { type: "address"; name: "recipient" }, + { type: "address"; name: "tokenOut" }, + { type: "uint256"; name: "amountIn" }, + { type: "uint256"; name: "minAmountOut" }, + { type: "uint256"; name: "deadline" }, + { type: "bytes"; name: "data" }, + ]; + }>; +}>; + +export const FN_SELECTOR = "0x5de3eedb" as const; +const FN_INPUTS = [ + { + name: "asset", + type: "address", + }, + { + components: [ + { + name: "recipient", + type: "address", + }, + { + name: "tokenOut", + type: "address", + }, + { + name: "amountIn", + type: "uint256", + }, + { + name: "minAmountOut", + type: "uint256", + }, + { + name: "deadline", + type: "uint256", + }, + { + name: "data", + type: "bytes", + }, + ], + name: "params", + type: "tuple", + }, +] as const; +const FN_OUTPUTS = [ + { + name: "amountIn", + type: "uint256", + }, + { + name: "amountOut", + type: "uint256", + }, +] as const; + +/** + * Checks if the `sellAsset` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `sellAsset` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isSellAssetSupported } from "thirdweb/extensions/assets"; + * + * const supported = isSellAssetSupported(["0x..."]); + * ``` + */ +export function isSellAssetSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "sellAsset" function. + * @param options - The options for the sellAsset function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeSellAssetParams } from "thirdweb/extensions/assets"; + * const result = encodeSellAssetParams({ + * asset: ..., + * params: ..., + * }); + * ``` + */ +export function encodeSellAssetParams(options: SellAssetParams) { + return encodeAbiParameters(FN_INPUTS, [options.asset, options.params]); +} + +/** + * Encodes the "sellAsset" function into a Hex string with its parameters. + * @param options - The options for the sellAsset function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeSellAsset } from "thirdweb/extensions/assets"; + * const result = encodeSellAsset({ + * asset: ..., + * params: ..., + * }); + * ``` + */ +export function encodeSellAsset(options: SellAssetParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeSellAssetParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "sellAsset" function on the contract. + * @param options - The options for the "sellAsset" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { sellAsset } from "thirdweb/extensions/assets"; + * + * const transaction = sellAsset({ + * contract, + * asset: ..., + * params: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function sellAsset( + options: BaseTransactionOptions< + | SellAssetParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [resolvedOptions.asset, resolvedOptions.params] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/setRewardLocker.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/setRewardLocker.ts new file mode 100644 index 00000000000..37d628ec69c --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/setRewardLocker.ts @@ -0,0 +1,142 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "setRewardLocker" function. + */ +export type SetRewardLockerParams = WithOverrides<{ + rewardLocker: AbiParameterToPrimitiveType<{ + type: "address"; + name: "rewardLocker"; + }>; +}>; + +export const FN_SELECTOR = "0xeb7fb197" as const; +const FN_INPUTS = [ + { + name: "rewardLocker", + type: "address", + }, +] as const; +const FN_OUTPUTS = [] as const; + +/** + * Checks if the `setRewardLocker` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `setRewardLocker` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isSetRewardLockerSupported } from "thirdweb/extensions/assets"; + * + * const supported = isSetRewardLockerSupported(["0x..."]); + * ``` + */ +export function isSetRewardLockerSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "setRewardLocker" function. + * @param options - The options for the setRewardLocker function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeSetRewardLockerParams } from "thirdweb/extensions/assets"; + * const result = encodeSetRewardLockerParams({ + * rewardLocker: ..., + * }); + * ``` + */ +export function encodeSetRewardLockerParams(options: SetRewardLockerParams) { + return encodeAbiParameters(FN_INPUTS, [options.rewardLocker]); +} + +/** + * Encodes the "setRewardLocker" function into a Hex string with its parameters. + * @param options - The options for the setRewardLocker function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeSetRewardLocker } from "thirdweb/extensions/assets"; + * const result = encodeSetRewardLocker({ + * rewardLocker: ..., + * }); + * ``` + */ +export function encodeSetRewardLocker(options: SetRewardLockerParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeSetRewardLockerParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "setRewardLocker" function on the contract. + * @param options - The options for the "setRewardLocker" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { setRewardLocker } from "thirdweb/extensions/assets"; + * + * const transaction = setRewardLocker({ + * contract, + * rewardLocker: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function setRewardLocker( + options: BaseTransactionOptions< + | SetRewardLockerParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [resolvedOptions.rewardLocker] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/setRouter.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/setRouter.ts new file mode 100644 index 00000000000..4fb04052854 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/setRouter.ts @@ -0,0 +1,139 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "setRouter" function. + */ +export type SetRouterParams = WithOverrides<{ + router: AbiParameterToPrimitiveType<{ type: "address"; name: "router" }>; +}>; + +export const FN_SELECTOR = "0xc0d78655" as const; +const FN_INPUTS = [ + { + name: "router", + type: "address", + }, +] as const; +const FN_OUTPUTS = [] as const; + +/** + * Checks if the `setRouter` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `setRouter` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isSetRouterSupported } from "thirdweb/extensions/assets"; + * + * const supported = isSetRouterSupported(["0x..."]); + * ``` + */ +export function isSetRouterSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "setRouter" function. + * @param options - The options for the setRouter function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeSetRouterParams } from "thirdweb/extensions/assets"; + * const result = encodeSetRouterParams({ + * router: ..., + * }); + * ``` + */ +export function encodeSetRouterParams(options: SetRouterParams) { + return encodeAbiParameters(FN_INPUTS, [options.router]); +} + +/** + * Encodes the "setRouter" function into a Hex string with its parameters. + * @param options - The options for the setRouter function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeSetRouter } from "thirdweb/extensions/assets"; + * const result = encodeSetRouter({ + * router: ..., + * }); + * ``` + */ +export function encodeSetRouter(options: SetRouterParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeSetRouterParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "setRouter" function on the contract. + * @param options - The options for the "setRouter" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { setRouter } from "thirdweb/extensions/assets"; + * + * const transaction = setRouter({ + * contract, + * router: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function setRouter( + options: BaseTransactionOptions< + | SetRouterParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [resolvedOptions.router] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetInfraDeployer/events/AssetInfraDeployed.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetInfraDeployer/events/AssetInfraDeployed.ts new file mode 100644 index 00000000000..2bc3f6be4c2 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetInfraDeployer/events/AssetInfraDeployed.ts @@ -0,0 +1,49 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareEvent } from "../../../../../event/prepare-event.js"; + +/** + * Represents the filters for the "AssetInfraDeployed" event. + */ +export type AssetInfraDeployedEventFilters = Partial<{ + implementation: AbiParameterToPrimitiveType<{ + type: "address"; + name: "implementation"; + indexed: true; + }>; + proxy: AbiParameterToPrimitiveType<{ + type: "address"; + name: "proxy"; + indexed: true; + }>; +}>; + +/** + * Creates an event object for the AssetInfraDeployed event. + * @param filters - Optional filters to apply to the event. + * @returns The prepared event object. + * @extension ASSETS + * @example + * ```ts + * import { getContractEvents } from "thirdweb"; + * import { assetInfraDeployedEvent } from "thirdweb/extensions/assets"; + * + * const events = await getContractEvents({ + * contract, + * events: [ + * assetInfraDeployedEvent({ + * implementation: ..., + * proxy: ..., + * }) + * ], + * }); + * ``` + */ +export function assetInfraDeployedEvent( + filters: AssetInfraDeployedEventFilters = {}, +) { + return prepareEvent({ + filters, + signature: + "event AssetInfraDeployed(address indexed implementation, address indexed proxy, bytes32 inputSalt, bytes data, bytes extraData)", + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/AssetInfraDeployer/write/deployInfraProxyDeterministic.ts b/packages/thirdweb/src/extensions/assets/__generated__/AssetInfraDeployer/write/deployInfraProxyDeterministic.ts new file mode 100644 index 00000000000..204dd2a6d36 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/AssetInfraDeployer/write/deployInfraProxyDeterministic.ts @@ -0,0 +1,187 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "deployInfraProxyDeterministic" function. + */ +export type DeployInfraProxyDeterministicParams = WithOverrides<{ + implementation: AbiParameterToPrimitiveType<{ + type: "address"; + name: "implementation"; + }>; + data: AbiParameterToPrimitiveType<{ type: "bytes"; name: "data" }>; + salt: AbiParameterToPrimitiveType<{ type: "bytes32"; name: "salt" }>; + extraData: AbiParameterToPrimitiveType<{ type: "bytes"; name: "extraData" }>; +}>; + +export const FN_SELECTOR = "0xb43c830c" as const; +const FN_INPUTS = [ + { + name: "implementation", + type: "address", + }, + { + name: "data", + type: "bytes", + }, + { + name: "salt", + type: "bytes32", + }, + { + name: "extraData", + type: "bytes", + }, +] as const; +const FN_OUTPUTS = [ + { + name: "deployedProxy", + type: "address", + }, +] as const; + +/** + * Checks if the `deployInfraProxyDeterministic` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `deployInfraProxyDeterministic` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isDeployInfraProxyDeterministicSupported } from "thirdweb/extensions/assets"; + * + * const supported = isDeployInfraProxyDeterministicSupported(["0x..."]); + * ``` + */ +export function isDeployInfraProxyDeterministicSupported( + availableSelectors: string[], +) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "deployInfraProxyDeterministic" function. + * @param options - The options for the deployInfraProxyDeterministic function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeDeployInfraProxyDeterministicParams } from "thirdweb/extensions/assets"; + * const result = encodeDeployInfraProxyDeterministicParams({ + * implementation: ..., + * data: ..., + * salt: ..., + * extraData: ..., + * }); + * ``` + */ +export function encodeDeployInfraProxyDeterministicParams( + options: DeployInfraProxyDeterministicParams, +) { + return encodeAbiParameters(FN_INPUTS, [ + options.implementation, + options.data, + options.salt, + options.extraData, + ]); +} + +/** + * Encodes the "deployInfraProxyDeterministic" function into a Hex string with its parameters. + * @param options - The options for the deployInfraProxyDeterministic function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeDeployInfraProxyDeterministic } from "thirdweb/extensions/assets"; + * const result = encodeDeployInfraProxyDeterministic({ + * implementation: ..., + * data: ..., + * salt: ..., + * extraData: ..., + * }); + * ``` + */ +export function encodeDeployInfraProxyDeterministic( + options: DeployInfraProxyDeterministicParams, +) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeDeployInfraProxyDeterministicParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "deployInfraProxyDeterministic" function on the contract. + * @param options - The options for the "deployInfraProxyDeterministic" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { deployInfraProxyDeterministic } from "thirdweb/extensions/assets"; + * + * const transaction = deployInfraProxyDeterministic({ + * contract, + * implementation: ..., + * data: ..., + * salt: ..., + * extraData: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function deployInfraProxyDeterministic( + options: BaseTransactionOptions< + | DeployInfraProxyDeterministicParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [ + resolvedOptions.implementation, + resolvedOptions.data, + resolvedOptions.salt, + resolvedOptions.extraData, + ] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/ERC20Asset/write/initialize.ts b/packages/thirdweb/src/extensions/assets/__generated__/ERC20Asset/write/initialize.ts new file mode 100644 index 00000000000..a9194516924 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/ERC20Asset/write/initialize.ts @@ -0,0 +1,189 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "initialize" function. + */ +export type InitializeParams = WithOverrides<{ + name: AbiParameterToPrimitiveType<{ type: "string"; name: "_name" }>; + symbol: AbiParameterToPrimitiveType<{ type: "string"; name: "_symbol" }>; + contractURI: AbiParameterToPrimitiveType<{ + type: "string"; + name: "_contractURI"; + }>; + maxSupply: AbiParameterToPrimitiveType<{ + type: "uint256"; + name: "_maxSupply"; + }>; + owner: AbiParameterToPrimitiveType<{ type: "address"; name: "_owner" }>; +}>; + +export const FN_SELECTOR = "0x30a8ff4e" as const; +const FN_INPUTS = [ + { + name: "_name", + type: "string", + }, + { + name: "_symbol", + type: "string", + }, + { + name: "_contractURI", + type: "string", + }, + { + name: "_maxSupply", + type: "uint256", + }, + { + name: "_owner", + type: "address", + }, +] as const; +const FN_OUTPUTS = [] as const; + +/** + * Checks if the `initialize` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `initialize` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isInitializeSupported } from "thirdweb/extensions/assets"; + * + * const supported = isInitializeSupported(["0x..."]); + * ``` + */ +export function isInitializeSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "initialize" function. + * @param options - The options for the initialize function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeInitializeParams } from "thirdweb/extensions/assets"; + * const result = encodeInitializeParams({ + * name: ..., + * symbol: ..., + * contractURI: ..., + * maxSupply: ..., + * owner: ..., + * }); + * ``` + */ +export function encodeInitializeParams(options: InitializeParams) { + return encodeAbiParameters(FN_INPUTS, [ + options.name, + options.symbol, + options.contractURI, + options.maxSupply, + options.owner, + ]); +} + +/** + * Encodes the "initialize" function into a Hex string with its parameters. + * @param options - The options for the initialize function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeInitialize } from "thirdweb/extensions/assets"; + * const result = encodeInitialize({ + * name: ..., + * symbol: ..., + * contractURI: ..., + * maxSupply: ..., + * owner: ..., + * }); + * ``` + */ +export function encodeInitialize(options: InitializeParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeInitializeParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "initialize" function on the contract. + * @param options - The options for the "initialize" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { initialize } from "thirdweb/extensions/assets"; + * + * const transaction = initialize({ + * contract, + * name: ..., + * symbol: ..., + * contractURI: ..., + * maxSupply: ..., + * owner: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function initialize( + options: BaseTransactionOptions< + | InitializeParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [ + resolvedOptions.name, + resolvedOptions.symbol, + resolvedOptions.contractURI, + resolvedOptions.maxSupply, + resolvedOptions.owner, + ] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/FeeManager/write/initialize.ts b/packages/thirdweb/src/extensions/assets/__generated__/FeeManager/write/initialize.ts new file mode 100644 index 00000000000..a21e466058c --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/FeeManager/write/initialize.ts @@ -0,0 +1,169 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "initialize" function. + */ +export type InitializeParams = WithOverrides<{ + owner: AbiParameterToPrimitiveType<{ type: "address"; name: "_owner" }>; + feeRecipient: AbiParameterToPrimitiveType<{ + type: "address"; + name: "_feeRecipient"; + }>; + defaultFee: AbiParameterToPrimitiveType<{ + type: "uint96"; + name: "_defaultFee"; + }>; +}>; + +export const FN_SELECTOR = "0xc861c250" as const; +const FN_INPUTS = [ + { + name: "_owner", + type: "address", + }, + { + name: "_feeRecipient", + type: "address", + }, + { + name: "_defaultFee", + type: "uint96", + }, +] as const; +const FN_OUTPUTS = [] as const; + +/** + * Checks if the `initialize` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `initialize` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isInitializeSupported } from "thirdweb/extensions/assets"; + * + * const supported = isInitializeSupported(["0x..."]); + * ``` + */ +export function isInitializeSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "initialize" function. + * @param options - The options for the initialize function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeInitializeParams } from "thirdweb/extensions/assets"; + * const result = encodeInitializeParams({ + * owner: ..., + * feeRecipient: ..., + * defaultFee: ..., + * }); + * ``` + */ +export function encodeInitializeParams(options: InitializeParams) { + return encodeAbiParameters(FN_INPUTS, [ + options.owner, + options.feeRecipient, + options.defaultFee, + ]); +} + +/** + * Encodes the "initialize" function into a Hex string with its parameters. + * @param options - The options for the initialize function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeInitialize } from "thirdweb/extensions/assets"; + * const result = encodeInitialize({ + * owner: ..., + * feeRecipient: ..., + * defaultFee: ..., + * }); + * ``` + */ +export function encodeInitialize(options: InitializeParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeInitializeParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "initialize" function on the contract. + * @param options - The options for the "initialize" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { initialize } from "thirdweb/extensions/assets"; + * + * const transaction = initialize({ + * contract, + * owner: ..., + * feeRecipient: ..., + * defaultFee: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function initialize( + options: BaseTransactionOptions< + | InitializeParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [ + resolvedOptions.owner, + resolvedOptions.feeRecipient, + resolvedOptions.defaultFee, + ] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +} diff --git a/packages/thirdweb/src/extensions/assets/__generated__/Router/write/initialize.ts b/packages/thirdweb/src/extensions/assets/__generated__/Router/write/initialize.ts new file mode 100644 index 00000000000..eeaae25ec04 --- /dev/null +++ b/packages/thirdweb/src/extensions/assets/__generated__/Router/write/initialize.ts @@ -0,0 +1,139 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; +import { once } from "../../../../../utils/promise/once.js"; + +/** + * Represents the parameters for the "initialize" function. + */ +export type InitializeParams = WithOverrides<{ + owner: AbiParameterToPrimitiveType<{ type: "address"; name: "_owner" }>; +}>; + +export const FN_SELECTOR = "0xc4d66de8" as const; +const FN_INPUTS = [ + { + name: "_owner", + type: "address", + }, +] as const; +const FN_OUTPUTS = [] as const; + +/** + * Checks if the `initialize` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `initialize` method is supported. + * @extension ASSETS + * @example + * ```ts + * import { isInitializeSupported } from "thirdweb/extensions/assets"; + * + * const supported = isInitializeSupported(["0x..."]); + * ``` + */ +export function isInitializeSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "initialize" function. + * @param options - The options for the initialize function. + * @returns The encoded ABI parameters. + * @extension ASSETS + * @example + * ```ts + * import { encodeInitializeParams } from "thirdweb/extensions/assets"; + * const result = encodeInitializeParams({ + * owner: ..., + * }); + * ``` + */ +export function encodeInitializeParams(options: InitializeParams) { + return encodeAbiParameters(FN_INPUTS, [options.owner]); +} + +/** + * Encodes the "initialize" function into a Hex string with its parameters. + * @param options - The options for the initialize function. + * @returns The encoded hexadecimal string. + * @extension ASSETS + * @example + * ```ts + * import { encodeInitialize } from "thirdweb/extensions/assets"; + * const result = encodeInitialize({ + * owner: ..., + * }); + * ``` + */ +export function encodeInitialize(options: InitializeParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeInitializeParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "initialize" function on the contract. + * @param options - The options for the "initialize" function. + * @returns A prepared transaction object. + * @extension ASSETS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { initialize } from "thirdweb/extensions/assets"; + * + * const transaction = initialize({ + * contract, + * owner: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function initialize( + options: BaseTransactionOptions< + | InitializeParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + accessList: async () => (await asyncOptions()).overrides?.accessList, + authorizationList: async () => + (await asyncOptions()).overrides?.authorizationList, + contract: options.contract, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + nonce: async () => (await asyncOptions()).overrides?.nonce, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [resolvedOptions.owner] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + }); +}