diff --git a/.github/workflows/suins-build-tx.yaml b/.github/workflows/suins-build-tx.yaml index ff783c14..a4a762ac 100644 --- a/.github/workflows/suins-build-tx.yaml +++ b/.github/workflows/suins-build-tx.yaml @@ -8,13 +8,11 @@ on: description: 'select transaction type to create' type: choice options: - - Authorize Basecamp Free Claim - Disable Discounts - Disable Free Claims - - Withdraw Auction Profits + - Profits to Treasury - Transfer Reserved Names - Main package upgrade - - Create Deepbook Pools sui_tools_image: description: 'image reference of sui_tools' default: 'mysten/sui-tools:mainnet' @@ -107,15 +105,15 @@ jobs: run: | cd scripts && pnpm transfer::names - - name: Withdraw Auction Profits - if: ${{ inputs.transaction_type == 'Withdraw Auction Profits' }} + - name: Profits to Treasury + if: ${{ inputs.transaction_type == 'Profits to Treasury' }} env: NODE_ENV: production GAS_OBJECT: ${{ inputs.gas_object_id }} NETWORK: mainnet ORIGIN: gh_action run: | - cd scripts && pnpm withdraw:auction:profits + cd scripts && pnpm withdraw:profits - name: Authorize Basecamp Free Claim if: ${{ inputs.transaction_type == 'Authorize Basecamp Free Claim' }} diff --git a/.gitignore b/.gitignore index 7ec9b1e6..48cb80ee 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ sui.log.* node_modules tx-data.txt* .DS_STORE* +published.json diff --git a/packages/renewal/sources/renew.move b/packages/renewal/sources/renew.move index 729b88de..3481da4f 100644 --- a/packages/renewal/sources/renew.move +++ b/packages/renewal/sources/renew.move @@ -50,7 +50,7 @@ module renewal::renew { /// and we can only have 1 config of each type in the suins app. /// We still set this up by using the default config functionality from suins package. /// The `public_key` passed in the `Config` can be a random u8 array with length 33. - public fun setup(cap: &AdminCap, suins: &mut SuiNS, config: Config) { + public fun setup(suins: &mut SuiNS, cap: &AdminCap, config: Config) { suins::add_config(cap, suins, RenewalConfig { config }); } diff --git a/packages/renewal/tests/renew_tests.move b/packages/renewal/tests/renew_tests.move index 2a4d95ae..bf169e4c 100644 --- a/packages/renewal/tests/renew_tests.move +++ b/packages/renewal/tests/renew_tests.move @@ -140,7 +140,7 @@ module renewal::renew_tests { REGULAR_PRICE * ::suins::constants::mist_per_sui(), ); - renewal::setup(&cap, &mut suins, config); + renewal::setup(&mut suins, &cap, config); let nft = registry.add_record(domain, 1,&clock, ctx); suins::add_registry(&cap, &mut suins, registry); diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 00000000..fc1c01fd --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,22 @@ +# Scripts + +This directory contains different scripts used to build transactions (for multi-sig operations). + + + +## Setup SuiNS locally + +To setup a local instance of SuiNS (or in any network of your choosing), all you need to do is call: + +``` +# choose from mainnet, testnet, devnet, localnet +export NETWORK=localnet +pnpm ts-node init/init.ts +``` + +This will automatically publish all the packages in the correct order, collect all the variables in a `published.json` +file, as well as do a full on-chain setup (creation of the registry, addition of pricelist, authorizing all apps). + +Then, you can use these published variables to the SDK and call different actions (e.g. registering names, subnames etc) + +> Do not check-in the `Move.lock` and `Move.toml` changes if you are submitting a PR. diff --git a/scripts/config/constants.ts b/scripts/config/constants.ts index 309e9787..e5495f38 100644 --- a/scripts/config/constants.ts +++ b/scripts/config/constants.ts @@ -2,7 +2,7 @@ import { normalizeSuiAddress } from "@mysten/sui.js/utils"; export type Network = 'mainnet' | 'testnet' -export type Config = Record +export type Config = Record<'mainnet' | 'testnet', PackageInfo> export type PackageInfo = { packageId: string; diff --git a/scripts/init/authorization.ts b/scripts/init/authorization.ts new file mode 100644 index 00000000..5b6fc38c --- /dev/null +++ b/scripts/init/authorization.ts @@ -0,0 +1,159 @@ +import { TransactionArgument, TransactionBlock } from "@mysten/sui.js/transactions"; + +/** + * A helper to authorize any app in the SuiNS object. + */ +export const authorizeApp = ({ + txb, adminCap, suins, type, suinsPackageIdV1 +}: { + txb: TransactionBlock; + adminCap: string; + suins: string; + type: string; + suinsPackageIdV1: string; +}) => { + console.log({adminCap, suins, type, suinsPackageIdV1}) + txb.moveCall({ + target: `${suinsPackageIdV1}::suins::authorize_app`, + arguments: [ + txb.object(adminCap), + txb.object(suins), + ], + typeArguments: [type], + }); +} + +/** + * A helper to deauthorize any app that has been authorized on the SuiNS object. + */ +export const deauthorizeApp = ({ + txb, adminCap, suins, type, suinsPackageIdV1 +}: { + txb: TransactionBlock; + adminCap: string; + suins: string; + type: string; + suinsPackageIdV1: string; +} +) => { + txb.moveCall({ + target: `${suinsPackageIdV1}::suins::deauthorize_app`, + arguments: [ + txb.object(adminCap), + txb.object(suins), + ], + typeArguments: [type], + }); +} + +/** + * A helper to call `setup` function for many apps that create a "registry" to hold state. + */ +export const setupApp = ({ + txb, adminCap, suins, target, args +}: { + txb: TransactionBlock; + adminCap: string; + suins: string; + target: `${string}::${string}`, + args?: TransactionArgument[]; +} +) => { + txb.moveCall({ + target: `${target}::setup`, + arguments: [ + txb.object(suins), + txb.object(adminCap), + ...(args || []) + ], + }); +} + +/** + * Add a config to the SuiNS object. + */ +export const addConfig = ({ + txb, adminCap, suins, type, config, suinsPackageIdV1 +}: { + txb: TransactionBlock; + adminCap: string; + suins: string; + suinsPackageIdV1: string; + config: TransactionArgument; + type: string; +}) => { + txb.moveCall({ + target: `${suinsPackageIdV1}::suins::add_config`, + arguments: [ + txb.object(adminCap), + txb.object(suins), + config + ], + typeArguments: [type] + }); +} + +/** + * Creates a default `config` which saves the price list and public key. + */ +export const newPriceConfig = ({ + txb, suinsPackageIdV1, priceList, publicKey = [...Array(33).keys()] +}: { + txb: TransactionBlock; + suinsPackageIdV1: string; + priceList: { [key: string]: number }; + publicKey?: number[]; + +}): TransactionArgument => { + return txb.moveCall({ + target: `${suinsPackageIdV1}::config::new`, + arguments: [ + txb.pure(publicKey), + txb.pure(priceList.three), + txb.pure(priceList.four), + txb.pure(priceList.fivePlus), + ], + }); + +} + +/** + * Add a registry to the SuiNS object. + */ +export const addRegistry = ({ + txb, adminCap, suins, type, registry, suinsPackageIdV1 +}: { + txb: TransactionBlock; + adminCap: string; + suins: string; + suinsPackageIdV1: string; + registry: TransactionArgument; + type: string; +}) => { + txb.moveCall({ + target: `${suinsPackageIdV1}::suins::add_registry`, + arguments: [ + txb.object(adminCap), + txb.object(suins), + registry + ], + typeArguments: [type] + }); +} + +/** + * Creates a default `registry` which saves direct/reverse lookups. + * That serves as the main registry for the SuiNS object after adding it. + */ +export const newLookupRegistry = ({ + txb, adminCap, suinsPackageIdV1 +}: { + txb: TransactionBlock; + adminCap: string; + suinsPackageIdV1: string; +}): TransactionArgument => { + return txb.moveCall({ + target: `${suinsPackageIdV1}::registry::new`, + arguments: [txb.object(adminCap)], + }); +} diff --git a/scripts/init/display_tp.ts b/scripts/init/display_tp.ts new file mode 100644 index 00000000..5d403516 --- /dev/null +++ b/scripts/init/display_tp.ts @@ -0,0 +1,55 @@ +import { TransactionBlock } from "@mysten/sui.js/transactions"; + +/** Creates the display. Should be called for both subnames and names. */ +export const createDisplay = ({ + txb, publisher, isSubdomain, suinsPackageIdV1 +}: { + txb: TransactionBlock; + publisher: string; + isSubdomain: boolean; + suinsPackageIdV1: string; +}) => { + + const display = txb.moveCall({ + target: `0x2::display::new`, + arguments: [txb.object(publisher)], + typeArguments: [ + isSubdomain ? `${suinsPackageIdV1}::subdomain_registration::SubDomainRegistration` : + `${suinsPackageIdV1}::suins_registration::SuinsRegistration`, + ], + }); + + txb.moveCall({ + target: `0x2::display::add_multiple`, + arguments: [ + display, + txb.pure(['name', 'link', 'image_url', 'description', 'project_url']), + txb.pure([ + `{${isSubdomain ? 'nft.' : ''}domain_name}`, + `https://{${isSubdomain ? 'nft.' : ''}domain_name}.id`, + `https://storage.googleapis.com/suins-nft-images/{${isSubdomain ? 'nft.' : ''}image_url}.png`, + 'SuiNS - Sculpt Your Identity', + 'https://suins.io', + ]), + ], + typeArguments: [ + isSubdomain ? `${suinsPackageIdV1}::subdomain_registration::SubDomainRegistration` : + `${suinsPackageIdV1}::suins_registration::SuinsRegistration`, + ], + }); + + txb.moveCall({ + target: `0x2::display::update_version`, + arguments: [display], + typeArguments: [ + isSubdomain ? `${suinsPackageIdV1}::subdomain_registration::SubDomainRegistration` : + `${suinsPackageIdV1}::suins_registration::SuinsRegistration`, + ], + }); + + const sender = txb.moveCall({ + target: '0x2::tx_context::sender' + }); + + txb.transferObjects([display], sender); +} diff --git a/scripts/init/init.ts b/scripts/init/init.ts new file mode 100644 index 00000000..3fe9962d --- /dev/null +++ b/scripts/init/init.ts @@ -0,0 +1,10 @@ +import { Network } from "./packages"; +import { publishPackages } from "./publish" +import { setup } from "./setup"; + +export const init = async (network: Network) => { + const published = await publishPackages(network); + await setup(published, network); +} + +init(process.env.NETWORK as Network); diff --git a/scripts/init/manifests.ts b/scripts/init/manifests.ts new file mode 100644 index 00000000..31ff4728 --- /dev/null +++ b/scripts/init/manifests.ts @@ -0,0 +1,40 @@ +export const SuiNS = (rev: string) => (packageId?: string) => `[package] +name = "suins" +version = "0.0.1" +edition = "2024.beta" +${packageId ? `published-at = "${packageId}"`: ''} + +[dependencies] +Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "${rev}" } + +[addresses] +suins = "${packageId || '0x0'}"`; + +export const SuiNSDependentPackages = (rev: string, name: string, extraDependencies?: string) => (packageId?: string) => `[package] +name = "${name}" +version = "0.0.1" +edition = "2024.beta" +${packageId ? `published-at = "${packageId}"`: ''} + +[dependencies] +Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "${rev}", override=true } +suins = { local = "../suins" } +${extraDependencies || ''} + +[addresses] +${name} = "${packageId || '0x0'}"`; + +export const TempSubdomainProxy = (rev: string) => (packageId?: string) => `[package] +name = "temp_subdomain_proxy" +version = "0.0.1" +edition = "2024.beta" +${packageId ? `published-at = "${packageId}"`: ''} + +[dependencies] +Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "${rev}", override=true } +subdomains = { local = "../subdomains" } +utils = { local = "../utils" } + +[addresses] +temp_subdomain_proxy = "${packageId || '0x0'}" +`; diff --git a/scripts/init/packages.ts b/scripts/init/packages.ts new file mode 100644 index 00000000..d7526bf3 --- /dev/null +++ b/scripts/init/packages.ts @@ -0,0 +1,257 @@ +import { SuiTransactionBlockResponse } from "@mysten/sui.js/client"; +import { SuiNS, SuiNSDependentPackages, TempSubdomainProxy } from "./manifests"; +import { TransactionBlock } from "@mysten/sui.js/transactions"; +import { addConfig, addRegistry, newLookupRegistry, newPriceConfig, setupApp } from "./authorization"; +import { createDisplay } from "./display_tp"; +import { MIST_PER_SUI } from "@mysten/sui.js/utils"; + +export type Network = 'mainnet' | 'testnet' | 'devnet' | 'localnet'; + + +const parseCorePackageObjects = (data: SuiTransactionBlockResponse) => { + const packageId = data.objectChanges!.find(x => x.type === 'published'); + if (!packageId || packageId.type !== 'published') throw new Error('Expected Published object'); + const upgradeCap = parseCreatedObject(data, '0x2::package::UpgradeCap'); + + return { + packageId: packageId.packageId, + upgradeCap: upgradeCap, + } +} + +const parseCreatedObject = (data: SuiTransactionBlockResponse, objectType: string) => { + const obj = data.objectChanges!.find(x => x.type === 'created' && x.objectType === objectType); + if (!obj || obj.type !== 'created') throw new Error(`Expected ${objectType} object`); + + return obj.objectId; +} + +export const Packages = (network: Network) => { + const rev = network === 'localnet' ? 'main' : `framework/${network}`; + const subdomainExtraDependencies = `denylist = { local = "../denylist" }`; + + return { + SuiNS: { + order: 1, + folder: 'suins', + manifest: SuiNS(rev), + processPublish: (data: SuiTransactionBlockResponse) => { + const { packageId, upgradeCap } = parseCorePackageObjects(data); + const publisher = parseCreatedObject(data, '0x2::package::Publisher'); + const suins = parseCreatedObject(data, `${packageId}::suins::SuiNS`); + const adminCap = parseCreatedObject(data, `${packageId}::suins::AdminCap`); + + return { + packageId, + upgradeCap, + publisher, + suins, + adminCap + } + }, + setupFunction: (txb: TransactionBlock, packageId: string, adminCap: string, suins: string, publisher: string) => { + // Adds the default registry where name records and reverse records will live + addRegistry({ + txb, + adminCap, + suins, + suinsPackageIdV1: packageId, + registry: newLookupRegistry({ txb, suinsPackageIdV1: packageId, adminCap: adminCap }), + type: `${packageId}::registry::Registry`, + }); + // Adds the configuration file (pricelist and public key) + addConfig({ + txb, + adminCap, + suins, + suinsPackageIdV1: packageId, + config: newPriceConfig({ txb, + suinsPackageIdV1: packageId, + priceList: { + three: 5 * Number(MIST_PER_SUI), + four: 2 * Number(MIST_PER_SUI), + fivePlus: 0.5 * Number(MIST_PER_SUI) + }}), + type: `${packageId}::config::Config`, + }); + // create display for names + createDisplay({ + txb, + publisher, + isSubdomain: false, + suinsPackageIdV1: packageId + }); + // create display for subnames + createDisplay({ + txb, + publisher, + isSubdomain: true, + suinsPackageIdV1: packageId + }); + } + }, + Utils: { + order: 2, + folder: 'utils', + manifest: SuiNSDependentPackages(rev, 'utils'), + processPublish: (data: SuiTransactionBlockResponse) => { + const { packageId, upgradeCap } = parseCorePackageObjects(data); + + return { + packageId, + upgradeCap, + authorizationType: `${packageId}::direct_setup::DirectSetup`, + } + } + }, + DenyList: { + order: 2, + folder: 'denylist', + manifest: SuiNSDependentPackages(rev, 'denylist'), + processPublish: (data: SuiTransactionBlockResponse) => { + const { packageId, upgradeCap } = parseCorePackageObjects(data); + + return { + packageId, + upgradeCap, + authorizationType: `${packageId}::denylist::DenyListAuth`, + } + }, + setupFunction: (txb: TransactionBlock, packageId: string, adminCap: string, suins: string) => { + setupApp({ txb, adminCap, suins, target: `${packageId}::denylist` }); + } + }, + Registration: { + order: 2, + folder: 'registration', + manifest: SuiNSDependentPackages(rev, 'registration'), + processPublish: (data: SuiTransactionBlockResponse) => { + const { packageId, upgradeCap } = parseCorePackageObjects(data); + + return { + packageId, + upgradeCap, + authorizationType: `${packageId}::register::Register`, + } + } + }, + Renewal: { + order: 2, + folder: 'renewal', + manifest: SuiNSDependentPackages(rev, 'renewal'), + processPublish: (data: SuiTransactionBlockResponse) => { + const { packageId, upgradeCap } = parseCorePackageObjects(data); + + return { + packageId, + upgradeCap, + authorizationType: `${packageId}::renew::Renew`, + } + }, + setupFunction: ({ + txb, + packageId, + adminCap, + suinsPackageIdV1, + suins, + priceList + } : { + txb: TransactionBlock, + packageId: string, + suinsPackageIdV1: string, + adminCap: string, + suins: string; + priceList: { [key: string]: number }; + } + ) => { + const configuration = newPriceConfig({ + txb, + suinsPackageIdV1, + priceList + }); + setupApp({ + txb, + adminCap, + suins: suins, + target: `${packageId}::renew::setup`, + args: [configuration] + }); + } + }, + DayOne: { + order: 2, + folder: 'day_one', + manifest: SuiNSDependentPackages(rev, 'day_one'), + processPublish: (data: SuiTransactionBlockResponse) => { + const { packageId, upgradeCap } = parseCorePackageObjects(data); + + return { + packageId, + upgradeCap, + authorizationType: `${packageId}::bogo::BogoApp`, + } + } + }, + Coupons: { + order: 2, + folder: 'coupons', + manifest: SuiNSDependentPackages(rev, 'coupons'), + processPublish: (data: SuiTransactionBlockResponse) => { + const { packageId, upgradeCap } = parseCorePackageObjects(data); + const couponHouse = parseCreatedObject(data, `${packageId}::coupons::CouponHouse`); + + return { + packageId, + upgradeCap, + authorizationType: `${packageId}::coupons::CouponsApp`, + couponHouse + } + } + }, + Subdomains: { + order: 3, + folder: 'subdomains', + manifest: SuiNSDependentPackages(rev, 'subdomains', subdomainExtraDependencies), + processPublish: (data: SuiTransactionBlockResponse) => { + const { packageId, upgradeCap } = parseCorePackageObjects(data); + + return { + packageId, + upgradeCap, + authorizationType: `${packageId}::subdomains::SubDomains`, + } + }, + setupFunction: (txb: TransactionBlock, packageId: string, adminCap: string, suins: string) => { + setupApp({ txb, adminCap, suins, target: `${packageId}::subdomains` }); + } + }, + Discounts: { + order: 3, + folder: 'discounts', + manifest: SuiNSDependentPackages(rev, 'discounts', 'day_one = { local = "../day_one" }'), + processPublish: (data: SuiTransactionBlockResponse) => { + const { packageId, upgradeCap } = parseCorePackageObjects(data); + const couponHouse = parseCreatedObject(data, `${packageId}::house::DiscountHouse`); + + return { + packageId, + upgradeCap, + authorizationType: `${packageId}::house::DiscountHouseApp`, + couponHouse + } + } + }, + TempSubdomainProxy: { + order: 3, + folder: 'temp_subdomain_proxy', + manifest: TempSubdomainProxy(rev), + processPublish: (data: SuiTransactionBlockResponse) => { + const { packageId, upgradeCap } = parseCorePackageObjects(data); + return { + packageId, + upgradeCap, + } + }, + }, + } +} diff --git a/scripts/init/publish.ts b/scripts/init/publish.ts new file mode 100644 index 00000000..4f6f2142 --- /dev/null +++ b/scripts/init/publish.ts @@ -0,0 +1,39 @@ +import path from "path" +import { Network, Packages } from "./packages" +import { writeFileSync } from "fs"; +import { TransactionBlock } from "@mysten/sui.js/transactions"; +import { publishPackage, signAndExecute } from "../utils/utils"; +import { PackageInfo } from "./types"; + +export const publishPackages = async (network: Network) => { + const packages = Packages(network); + const contractsPath = path.resolve(__dirname, '../../packages'); + const results: Record> = {}; + + // split by ordering, and publish in batch. + const orderings = [...new Set([...Object.values(packages).map(x => x.order)])]; + + // We do the publishing in batches, because some + for(const ordering of orderings) { + const list = Object.entries(packages).filter(x => x[1].order === ordering); + + for (const [key, pkg] of list) { + const packageFolder = path.resolve(contractsPath, pkg.folder); + const manifestFile = path.resolve(packageFolder + '/Move.toml'); + writeFileSync(manifestFile, pkg.manifest()); // save the manifest as is. + + const txb = new TransactionBlock(); + publishPackage(txb, packageFolder, network); + const res = await signAndExecute(txb, network); + + // @ts-ignore-next-line + const data = pkg.processPublish(res); + results[key] = data; + + writeFileSync(manifestFile, pkg.manifest(data.packageId)); // update the manifest with the published-at field. + } + } + writeFileSync(path.resolve(path.resolve(__dirname, '../'), 'published.json'), JSON.stringify(results, null, 2)); + console.log("******* Packages published successfully *******"); + return results as PackageInfo; +} diff --git a/scripts/init/setup.ts b/scripts/init/setup.ts new file mode 100644 index 00000000..95b16651 --- /dev/null +++ b/scripts/init/setup.ts @@ -0,0 +1,50 @@ +import { TransactionBlock } from "@mysten/sui.js/transactions"; +import { Network, Packages } from "./packages"; +import { authorizeApp } from "./authorization"; +import packageInfo from "../published.json"; +import { signAndExecute } from "../utils/utils"; +import { PackageInfo } from "./types"; +import { MIST_PER_SUI } from "@mysten/sui.js/utils"; + +export const setup = async (packageInfo: PackageInfo, network: Network) => { + const packages = Packages(network); + + const txb = new TransactionBlock(); + + for(const pkg of Object.values(packageInfo)) { + if ('authorizationType' in pkg && pkg.authorizationType) { + authorizeApp({ + txb, + adminCap: packageInfo.SuiNS.adminCap, + suins: packageInfo.SuiNS.suins, + type: pkg.authorizationType, + suinsPackageIdV1: packageInfo.SuiNS.packageId + }); + } + } + // Call setup functions for our packages. + packages.Subdomains.setupFunction(txb, packageInfo.Subdomains.packageId, packageInfo.SuiNS.adminCap, packageInfo.SuiNS.suins); + packages.DenyList.setupFunction(txb, packageInfo.DenyList.packageId, packageInfo.SuiNS.adminCap, packageInfo.SuiNS.suins); + packages.SuiNS.setupFunction(txb, packageInfo.SuiNS.packageId, packageInfo.SuiNS.adminCap, packageInfo.SuiNS.suins, packageInfo.SuiNS.publisher); + packages.Renewal.setupFunction({ + txb, + adminCap: packageInfo.SuiNS.adminCap, + suins: packageInfo.SuiNS.suins, + packageId: packageInfo.Renewal.packageId, + suinsPackageIdV1: packageInfo.SuiNS.packageId, + priceList: { + three: 2 * Number(MIST_PER_SUI), + four: 1 * Number(MIST_PER_SUI), + fivePlus: 0.2 * Number(MIST_PER_SUI) + } + }); + + try{ + await signAndExecute(txb, network); + console.log("******* Packages set up successfully *******"); + + }catch(e) { + console.error("Something went wrong!"); + console.dir(e, { depth: null }) + } +} diff --git a/scripts/init/types.ts b/scripts/init/types.ts new file mode 100644 index 00000000..dd4913e2 --- /dev/null +++ b/scripts/init/types.ts @@ -0,0 +1,29 @@ +export type PackageInfo = { + SuiNS: SuiNS; + Utils: Package; + DenyList: Package; + Registration: Package; + Renewal: Package; + DayOne: Package; + Coupons: Coupons; + Subdomains: Package; + Discounts: Package; + TempSubdomainProxy: Package; +} + +export type Package = { + packageId: string; + upgradeCap: string; + authorizationType?: string; +} +export type Coupons = Package & { + couponHouse: string; +} + +export type SuiNS = { + packageId: string; + upgradeCap: string; + publisher: string; + suins: string; + adminCap: string; +} diff --git a/scripts/package.json b/scripts/package.json index 6165e265..7a8670c4 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -7,7 +7,7 @@ "test": "echo \"Error: no test specified\" && exit 1", "transactions::main_package::upgrade": "ts-node transactions/main_package_upgrade.ts", "transfer::names": "ts-node reserved-names/transfer-names.ts", - "withdraw:auction:profits": "ts-node transactions/withdraw_funds_20290927.ts", + "withdraw:profits": "ts-node transactions/funds_to_treasury.ts", "authorize-utils": "ts-node transactions/authorize_utils.ts", "authorize-discounts": "ts-node transactions/basecamp/basecamp_free_claims.ts", "disable-free-claims": "ts-node transactions/quest3/disable_free_claims.ts", diff --git a/scripts/transactions/withdraw_funds_20290927.ts b/scripts/transactions/funds_to_treasury.ts similarity index 100% rename from scripts/transactions/withdraw_funds_20290927.ts rename to scripts/transactions/funds_to_treasury.ts diff --git a/scripts/transactions/renewals/authorize_renewals.ts b/scripts/transactions/renewals/authorize_renewals.ts index 97da4f22..90ec066c 100644 --- a/scripts/transactions/renewals/authorize_renewals.ts +++ b/scripts/transactions/renewals/authorize_renewals.ts @@ -7,39 +7,33 @@ import { MIST_PER_SUI } from "@mysten/sui.js/utils"; import { Network, mainPackage } from "../../config/constants"; import { TransactionBlock } from "@mysten/sui.js/transactions"; import { prepareMultisigTx, signAndExecute } from "../../utils/utils"; +import { Packages } from "../../init/packages"; +import { authorizeApp } from "../../init/authorization"; export const authorize = async (network: Network) => { const txb = new TransactionBlock(); - const config = mainPackage[network]; - txb.moveCall({ - target: `${config.packageId}::suins::authorize_app`, - arguments: [ - txb.object(config.adminCap), - txb.object(config.suins), - ], - typeArguments: [`${config.renewalsPackageId}::renew::Renew`], - }); - - const configuration = txb.moveCall({ - target: `${config.packageId}::config::new`, - arguments: [ - txb.pure([...Array(33).keys()]), - txb.pure(50n * MIST_PER_SUI), - txb.pure(10n * MIST_PER_SUI), - txb.pure(2n * MIST_PER_SUI), - ], - }); - txb.moveCall({ - target: `${config.renewalsPackageId}::renew::setup`, - arguments: [ - txb.object(config.adminCap), - txb.object(config.suins), - configuration, - ], - typeArguments: [], - }); + authorizeApp({ + txb, + adminCap: config.adminCap, + suins: config.suins, + type: `${config.renewalsPackageId}::renew::Renew`, + suinsPackageIdV1: config.packageId + }); + + Packages('mainnet').Renewal.setupFunction({ + txb, + adminCap: config.adminCap, + suins: config.suins, + packageId: config.renewalsPackageId, + suinsPackageIdV1: config.packageId, + priceList: { + three: 50 * Number(MIST_PER_SUI), + four: 10 * Number(MIST_PER_SUI), + fivePlus: 2 * Number(MIST_PER_SUI) + } + }); // for mainnet, we just prepare multisig TX if(network === 'mainnet') return prepareMultisigTx(txb, 'mainnet'); diff --git a/scripts/transactions/renewals/publish_renewals.ts b/scripts/transactions/renewals/publish_renewals.ts deleted file mode 100644 index f4e8c643..00000000 --- a/scripts/transactions/renewals/publish_renewals.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2023, Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import dotenv from "dotenv"; -dotenv.config(); -import { execSync } from 'child_process'; - -const gasObject = process.env.GAS_OBJECT; - -// Github actions are always on mainnet. -const publish = async () => { - - if(!gasObject) throw new Error("Gas Object not supplied for a mainnet transaction"); - - // on GH Action, the sui binary is located on root. Referencing that as `/` doesn't work. - const suiFolder = process.env.ORIGIN === 'gh_action' ? '../../sui' : 'sui'; - const publishCall = `${suiFolder} client publish --gas-budget 3000000000 --gas ${gasObject} --serialize-unsigned-transaction --skip-dependency-verification` - - // to suins/..(packages)/..(base)/scripts/tx/tx-data.txt - execSync(`cd $PWD/../packages/renewal && ${publishCall} > $PWD/../../scripts/tx/tx-data.txt`); -} - -publish(); diff --git a/scripts/utils/utils.ts b/scripts/utils/utils.ts index 0790ce02..d444f7fd 100644 --- a/scripts/utils/utils.ts +++ b/scripts/utils/utils.ts @@ -7,10 +7,9 @@ import { getFullnodeUrl, ExecutionStatus, GasCostSummary, SuiClient, SuiTransact import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; import { TransactionArgument, TransactionBlock } from '@mysten/sui.js/transactions'; import { fromB64 } from '@mysten/sui.js/utils'; -import { execSync } from "child_process"; +import { execFileSync, execSync } from "child_process"; import { toB64 } from "@mysten/sui.js/utils"; - -export type Network = 'mainnet' | 'testnet' | 'devnet' | 'localnet' +import { Network } from "../init/packages"; const SUI = `sui`; @@ -18,6 +17,25 @@ export const getActiveAddress = () => { return execSync(`${SUI} client active-address`, { encoding: 'utf8' }).trim(); } +export const publishPackage = (txb: TransactionBlock, path: string, network: Network) => { + const { modules, dependencies } = JSON.parse( + execFileSync( + 'sui', + ['move', 'build', '--dump-bytecode-as-base64', '--path', path], + { encoding: 'utf-8' }, + ), + ); + + const cap = txb.publish({ + modules, + dependencies, + }); + + // Transfer the upgrade capability to the sender so they can upgrade the package later if they want. + txb.transferObjects([cap], txb.pure.address(getActiveAddress())); +} + + /// Returns a signer based on the active address of system's sui. export const getSigner = () => { const sender = getActiveAddress(); @@ -129,4 +147,4 @@ async function inspectTransaction(tx: TransactionBlock, client: SuiClient) { console.dir(result, { depth: null }); return result.effects.status.status === 'success' -} \ No newline at end of file +}