diff --git a/docs/.vuepress/configs/sidebar.ts b/docs/.vuepress/configs/sidebar.ts index 75b34fe..618a9fc 100644 --- a/docs/.vuepress/configs/sidebar.ts +++ b/docs/.vuepress/configs/sidebar.ts @@ -72,6 +72,7 @@ export const sidebar: Record = { '/build/sdk/tokens.md', '/build/sdk/examples-nesting.md', '/build/sdk/refungible.md', + '/build/sdk/sponsoring.md', ] }, { @@ -80,8 +81,18 @@ export const sidebar: Record = { '/build/evm', '/build/evm/accounts.md', '/build/evm/evm-from-substrate.md', + { + text: 'Precompiles', + link: '/build/evm/precompiles/index.md', + collapsible: true, + children: [ + '/build/evm/precompiles/index.md', + '/build/evm/precompiles/contract-helpers.md', + '/build/evm/precompiles/collection-helpers.md', + ], + }, '/build/evm/smart_contracts.md', - '/build/evm/UniqueNFT.md' + '/build/evm/UniqueNFT.md', ], } ], @@ -204,7 +215,9 @@ export const sidebar: Record = { '/reference/blockchain/owner-admin-roles.md', '/reference/blockchain/rpc.md', '/reference/blockchain/extrinsics.md', - '/reference/blockchain/events.md', ], + '/reference/blockchain/events.md', + '/reference/blockchain/contract-helpers.md' + ], }, { text: 'Schemas', diff --git a/docs/build/evm/index.md b/docs/build/evm/index.md index 6d7e86e..f590fbb 100644 --- a/docs/build/evm/index.md +++ b/docs/build/evm/index.md @@ -6,6 +6,12 @@ Unique Network employs Substrate’s flexibility to deliver native NFT features, This documentation will guide you through deploying and interacting with NFTs via the EVM layer, offering a comprehensive toolkit for both Substrate and Ethereum developers. +## Navigation + +1. To understand how compatibility between Substrate and Ethereum accounts is achieved, see the [Account mirrors](./accounts.md) section. +2. To learn how Ethereum smart contracts can be called from Substrate, visit the [EVM from Substrate](./evm-from-substrate.md) section. +3. If you're interested in advanced features like creating native NFTs, nesting, and providing a gasless experience, explore the [Precompiles](/build/evm/precompiles/index.md) section. + ## Connect to the EVM on Unique Network You can connect to Unique utilizing familiar tools such as MetaMask and Ethers.js. These tools allow developers to interact with and deploy smart contracts as they would on any Ethereum-compatible network. diff --git a/docs/build/evm/precompiles/collection-helpers.md b/docs/build/evm/precompiles/collection-helpers.md new file mode 100644 index 0000000..74be809 --- /dev/null +++ b/docs/build/evm/precompiles/collection-helpers.md @@ -0,0 +1,23 @@ +# Collection Helpers + +Address: **0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f** + +This precompiled contract enables the creation of native collections and tokens via the Ethereum interface. + +## Code examples + +Below are examples of how to use this precompiled contract with ethers.js and hardhat. + +> If you're unfamiliar with setting up a Hardhat project, refer to the official documentation: https://hardhat.org/docs + +### Connect to contract + +```ts +import { ethers } from 'hardhat'; +import { CollectionHelpers__factory } from '@unique-nft/solidity-interfaces'; + +const [signer] = await ethers.getSigners(); + +const collectionHelpers = CollectionHelpers__factory + .connect("0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f", signer); +``` \ No newline at end of file diff --git a/docs/build/evm/precompiles/contract-helpers.md b/docs/build/evm/precompiles/contract-helpers.md new file mode 100644 index 0000000..7e3ead3 --- /dev/null +++ b/docs/build/evm/precompiles/contract-helpers.md @@ -0,0 +1,98 @@ +# Contract Helpers + +Address: **0x842899ecf380553e8a4de75bf534cdf6fbf64049** + +This precompiled contract allows the owner to manage the sponsorship of their contract. + +In Unique Network, transactions can be sponsored, allowing for a gasless experience where the sponsor covers the transaction fees. This enables seamless and cost-free transfers of NFTs and the execution of smart contracts, even for accounts without native tokens. + +[[toc]] + +## Interface + +Check the [reference section](/reference/blockchain/contract-helpers.md) for the complete interface details + +## Code examples + +Below are examples of how to use this precompiled contract with ethers.js and hardhat. + +> If you're unfamiliar with setting up a Hardhat project, refer to the official documentation: https://hardhat.org/docs + +### Connect to contract + +First, let's deploy the smart contract to be sponsored and connect to ContractHelpers precompile. We assume you have developed a contract called MyContract.sol and want to sponsor its calls. + +```ts +import { ethers } from 'hardhat'; +import { ContractHelpers__factory } from '@unique-nft/solidity-interfaces'; + +const [signer] = await ethers.getSigners(); + +const MyContractFactory = await ethers.getContractFactory('MyContract', seller); + +// Contract to be sponsored +const myContract = await MyContractFactory.deploy(); +myContract.waitForDeployment(); + +const contractHelpers = ContractHelpers__factory + .connect("0x842899ecf380553e8a4de75bf534cdf6fbf64049", signer); +``` + +## Choose sponsoring mode + +### Self-sponsoring + +The simplest option is to sponsor transactions directly from the contract address itself. + +```ts +await contractHelpers.selfSponsoredEnable(await myContract.getAddress()); + +const hasSponsor = await contractHelpers.hasSponsor(myContract.getAddress()); +console.log("Self sponsoring enabled: ", hasSponsor); // true +``` + +### External address sponsoring + +You can also set up sponsorship from an arbitrary address. In this case, one additional step is required – the sponsor must confirm the sponsorship. + +```ts +await contractHelpers.selfSponsoredEnable(await myContract.getAddress()); + +const hasSponsor = await contractHelpers.hasSponsor(myContract.getAddress()); +console.log("Self sponsoring enabled: ", hasSponsor); // true +``` + +### Enable sponsoring + +There are a couple more steps to enable gasless transactions. + +1. There are three sponsoring modes: + +- 0: Disabled (default) +- 1: Allowlisted (Only users from allowlist will be sponsored) +- 2: Generous (All users will be sponsored) + +Let's configure the contract to sponsor transactions for all users. + +2. By default, not every block is sponsored due to a timeout. Let's adjust this setting. + +```ts +// Sponsoring is Disabled by default: +const sponsoringEnabled = await contractHelpers.sponsoringEnabled(myContract.getAddress()); +console.log("Is sponsoring enabled?", sponsoringEnabled); + +// Set to 2 - Generous mode +await contractHelpers.setSponsoringMode(myContract.getAddress(), 2); +// Set to 0 - Sponsor transactions in every block +await contractHelpers.setSponsoringRateLimit(myContract.getAddress(), 0); + +// Optionally, you can limit the maximum fee amount you want to sponsor +// await contractHelpers.setSponsoringFeeLimit(myContract.getAddress(), ...); + +const sponsoringEnabledAfter = await contractHelpers.sponsoringEnabled(myContract.getAddress()); +console.log("Sponsoring enabled now:", sponsoringEnabledAfter); +``` + +## Setting up Metamask + +When sending transactions through Metamask, it initially verifies if the user has sufficient balance to cover gas fees. To enable sponsoring with Metamask, we need to bypass this gas check. Use the following [library](https://github.com/UniqueNetwork/web3-provider-sponsoring). diff --git a/docs/build/evm/precompiles/index.md b/docs/build/evm/precompiles/index.md new file mode 100644 index 0000000..537d7e6 --- /dev/null +++ b/docs/build/evm/precompiles/index.md @@ -0,0 +1,10 @@ +# Intro + +Unique Network offers a suite of precompiled contracts that enable interaction with advanced features through the Ethereum interface. + +To integrate these capabilities into your application, use the [@unique-nft/solidity-interfaces](https://www.npmjs.com/package/@unique-nft/solidity-interfaces) library. + +|Precompile|Features|Address| +|:-|:------|:---| +|[Contract Helpers](./contract-helpers.md)|Manage contract sponsoring|0x842899ecf380553e8a4de75bf534cdf6fbf64049| +|[Collection Helpers](./collection-helpers.md)|Create native collection and tokens|0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f| \ No newline at end of file diff --git a/docs/build/evm/todo-setting-project.md b/docs/build/evm/todo-setting-project.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/build/sdk/sponsoring.md b/docs/build/sdk/sponsoring.md new file mode 100644 index 0000000..7acb0dc --- /dev/null +++ b/docs/build/sdk/sponsoring.md @@ -0,0 +1,227 @@ +# Transaction sponsoring + +In Unique Network, transactions can be sponsored, allowing for a gasless experience where the sponsor covers the transaction fees. This enables seamless and cost-free transfers of NFTs and the execution of smart contracts, even for accounts without native tokens. + +[[toc]] + +## Collection sponsoring + + + + +Let's start with a full code example and then break it down. + +```ts +import { Sdk, CHAIN_CONFIG } from "@unique-nft/sdk/full"; +import { Sr25519Account } from "@unique-nft/sdk/sr25519"; + +const main = async () => { + // 0. Initialize accounts + // Set up sponsor and empty accounts + const sponsorMnemonic = "..."; + const sponsor = Sr25519Account.fromUri(sponsorMnemonic); + const emptyAccount = Sr25519Account.fromUri( + Sr25519Account.generateMnemonic(), + ); + + // 0.1. Initialize SDK with sponsor + // Set SDK with sponsor as default signer + const sdk = new Sdk({ + baseUrl: CHAIN_CONFIG.opal.restUrl, + account: sponsor, + }); + + // 1. Sponsor creates a collection + // Create a new collection by sponsor + const collectionResponse = await sdk.collection.create({ + name: "Sponsored", + description: "This collection is sponsored", + tokenPrefix: "SC", + }); + + const { collectionId } = collectionResponse.parsed!; + + // 2. Create NFT + // Create an NFT in the collection + console.log("Creating NFT"); + const nftResponse = await sdk.token.create({ collectionId }); + + const nft = nftResponse.parsed!; + + // 3. Set sponsorship for the collection + // Make transactions for the collection gasless + + // 3.1. Set sponsor address + // Set sponsor address for collection transactions + await sdk.collection.setSponsorship({ + collectionId, + newSponsor: sponsor.address, + }); + + // 3.2. Confirm sponsorship + // Sponsor confirms sponsorship + await sdk.collection.confirmSponsorship({ collectionId }); + + // 3.3. Set sponsorship limits + // Set limits for sponsorship; sponsor all transfers + await sdk.collection.setLimits({ + collectionId, + limits: { sponsorTransferTimeout: 0 }, + }); + + // 4. Test sponsorship + // Test the sponsorship functionality + + // 4.1. Sponsor transfers NFT to emptyAccount + // Sponsor transfers NFT to empty account + await sdk.token.transfer({ ...nft, to: emptyAccount.address }); + + { + // 4.2. Check new owner + // Verify the empty account owns the NFT + const { owner } = await sdk.token.owner(nft); + if (owner !== emptyAccount.address) + throw Error("Empty account is not the owner of NFT"); + } + + // 4.3. Empty account transfers token + // Empty account transfers NFT, gas paid by sponsor + const { fee } = await sdk.token.transfer( + { ...nft, to: sponsor.address, address: emptyAccount.address }, + { signer: emptyAccount.signer }, + ); + console.log("Gasless transfer fee:", fee?.raw); + + // 4.4. Check NFT owner is sponsor again + // Verify sponsor owns the NFT again + console.log("Check NFT owner is sponsor again"); + const { owner } = await sdk.token.owner(nft); + if (owner !== sponsor.address) throw Error("Sponsor is not the owner of NFT"); +}; + +main(); +``` + +#### 0. Initialize Accounts and SDK + +Start by setting up the necessary accounts. The sponsor account must have a balance of native tokens to cover transaction fees, while the empty account will perform gasless transfers. + +Initialize the SDK with the sponsor account set as the default signer. + +```ts +// 0. Initialize accounts +// Set up sponsor and empty accounts +const sponsorMnemonic = "..."; +const sponsor = Sr25519Account.fromUri(sponsorMnemonic); +const emptyAccount = Sr25519Account.fromUri( + Sr25519Account.generateMnemonic(), +); + +// 0.1. Initialize SDK with sponsor +// Set SDK with sponsor as default signer +const sdk = new Sdk({ + baseUrl: CHAIN_CONFIG.opal.restUrl, + account: sponsor, +}); +``` + +#### 1. Create Collection and NFT + +The sponsor creates a new NFT collection and a token on its own address. + +```ts +// 1. Sponsor creates a collection +// Create a new collection by sponsor +const collectionResponse = await sdk.collection.create({ + name: "Sponsored", + description: "This collection is sponsored", + tokenPrefix: "SC", +}); + +const { collectionId } = collectionResponse.parsed!; + +// 2. Create NFT +// Create an NFT in the collection +console.log("Creating NFT"); +const nftResponse = await sdk.token.create({ collectionId }); + +const nft = nftResponse.parsed!; +``` + +#### 2. Set Sponsorship for the Collection + +Configure the collection to allow gasless transactions, meaning the `sponsor` will cover the transaction fees. + +```ts +// 3. Set sponsorship for the collection +// Make transactions for the collection gasless + +// 3.1. Set sponsor address +// Set sponsor address for collection transactions +await sdk.collection.setSponsorship({ + collectionId, + newSponsor: sponsor.address, +}); +``` + +Now the sponsor we set on a previous step should confirms their sponsorship for the collection. + +```ts + // 3.2. Confirm sponsorship + // Sponsor confirms sponsorship + await sdk.collection.confirmSponsorship({ collectionId }); +``` + +By default, there is a cooldown period of five blocks between transactions. During this period, transaction fees are withdrawn from transaction signers as usual. + +Let's define the limits for sponsorship to ensure the sponsor covers the fees for all transfers within the collection. + +```ts +// 3.3. Set sponsorship limits +// Set limits for sponsorship; sponsor all transfers +await sdk.collection.setLimits({ + collectionId, + limits: { sponsorTransferTimeout: 0 }, +}); +``` + +#### 3. Test sponsorship + +Now let's test it. Send the previously created NFT to the empty account. After that, the empty account will send the NFT back even though it does not have any native tokens. The transaction fees will be withdrawn from the sponsor's balance. + +```ts +// 4. Test sponsorship +// Test the sponsorship functionality + +// 4.1. Sponsor transfers NFT to emptyAccount +// Sponsor transfers NFT to empty account +await sdk.token.transfer({ ...nft, to: emptyAccount.address }); + +{ + // 4.2. Check new owner + // Verify the empty account owns the NFT + const { owner } = await sdk.token.owner(nft); + if (owner !== emptyAccount.address) + throw Error("Empty account is not the owner of NFT"); +} + +// 4.3. Empty account transfers token +// Empty account transfers NFT, gas paid by sponsor +const { fee } = await sdk.token.transfer( + { ...nft, to: sponsor.address, address: emptyAccount.address }, + { signer: emptyAccount.signer }, +); +console.log("Gasless transfer fee:", fee?.raw); + +// 4.4. Check NFT owner is sponsor again +// Verify sponsor owns the NFT again +console.log("Check NFT owner is sponsor again"); +const { owner } = await sdk.token.owner(nft); +if (owner !== sponsor.address) throw Error("Sponsor is not the owner of NFT"); +``` + +## Contract sponsoring + +Review the [EVM section](/build/evm/precompiles/index.md) for contract sponsorship details. \ No newline at end of file diff --git a/docs/reference/blockchain/ContractHelpers.sol b/docs/reference/blockchain/ContractHelpers.sol new file mode 100644 index 0000000..39fe4ac --- /dev/null +++ b/docs/reference/blockchain/ContractHelpers.sol @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: OTHER +// This code is automatically generated + +pragma solidity >=0.8.0 <0.9.0; + +/// @dev common stubs holder +interface Dummy { + +} + +interface ERC165 is Dummy { + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} + +/// @dev inlined interface +interface ContractHelpersEvents { + event ContractSponsorSet(address indexed contractAddress, address sponsor); + event ContractSponsorshipConfirmed(address indexed contractAddress, address sponsor); + event ContractSponsorRemoved(address indexed contractAddress); +} + +/// @title Magic contract, which allows users to reconfigure other contracts +/// @dev the ERC-165 identifier for this interface is 0x30afad04 +interface ContractHelpers is Dummy, ERC165, ContractHelpersEvents { + /// Get user, which deployed specified contract + /// @dev May return zero address in case if contract is deployed + /// using uniquenetwork evm-migration pallet, or using other terms not + /// intended by pallet-evm + /// @dev Returns zero address if contract does not exists + /// @param contractAddress Contract to get owner of + /// @return address Owner of contract + /// @dev EVM selector for this function is: 0x5152b14c, + /// or in textual repr: contractOwner(address) + function contractOwner(address contractAddress) external view returns (address); + + /// Set sponsor. + /// @param contractAddress Contract for which a sponsor is being established. + /// @param sponsor User address who set as pending sponsor. + /// @dev EVM selector for this function is: 0xf01fba93, + /// or in textual repr: setSponsor(address,address) + function setSponsor(address contractAddress, address sponsor) external; + + /// Set contract as self sponsored. + /// + /// @param contractAddress Contract for which a self sponsoring is being enabled. + /// @dev EVM selector for this function is: 0x89f7d9ae, + /// or in textual repr: selfSponsoredEnable(address) + function selfSponsoredEnable(address contractAddress) external; + + /// Remove sponsor. + /// + /// @param contractAddress Contract for which a sponsorship is being removed. + /// @dev EVM selector for this function is: 0xef784250, + /// or in textual repr: removeSponsor(address) + function removeSponsor(address contractAddress) external; + + /// Confirm sponsorship. + /// + /// @dev Caller must be same that set via [`setSponsor`]. + /// + /// @param contractAddress Сontract for which need to confirm sponsorship. + /// @dev EVM selector for this function is: 0xabc00001, + /// or in textual repr: confirmSponsorship(address) + function confirmSponsorship(address contractAddress) external; + + /// Get current sponsor. + /// + /// @param contractAddress The contract for which a sponsor is requested. + /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. + /// @dev EVM selector for this function is: 0x766c4f37, + /// or in textual repr: sponsor(address) + function sponsor(address contractAddress) external view returns (OptionCrossAddress memory); + + /// Check tat contract has confirmed sponsor. + /// + /// @param contractAddress The contract for which the presence of a confirmed sponsor is checked. + /// @return **true** if contract has confirmed sponsor. + /// @dev EVM selector for this function is: 0x97418603, + /// or in textual repr: hasSponsor(address) + function hasSponsor(address contractAddress) external view returns (bool); + + /// Check tat contract has pending sponsor. + /// + /// @param contractAddress The contract for which the presence of a pending sponsor is checked. + /// @return **true** if contract has pending sponsor. + /// @dev EVM selector for this function is: 0x39b9b242, + /// or in textual repr: hasPendingSponsor(address) + function hasPendingSponsor(address contractAddress) external view returns (bool); + + /// @dev EVM selector for this function is: 0x6027dc61, + /// or in textual repr: sponsoringEnabled(address) + function sponsoringEnabled(address contractAddress) external view returns (bool); + + /// @dev EVM selector for this function is: 0xfde8a560, + /// or in textual repr: setSponsoringMode(address,uint8) + function setSponsoringMode(address contractAddress, SponsoringModeT mode) external; + + /// Get current contract sponsoring rate limit + /// @param contractAddress Contract to get sponsoring rate limit of + /// @return uint32 Amount of blocks between two sponsored transactions + /// @dev EVM selector for this function is: 0xf29694d8, + /// or in textual repr: sponsoringRateLimit(address) + function sponsoringRateLimit(address contractAddress) external view returns (uint32); + + /// Set contract sponsoring rate limit + /// @dev Sponsoring rate limit - is a minimum amount of blocks that should + /// pass between two sponsored transactions + /// @param contractAddress Contract to change sponsoring rate limit of + /// @param rateLimit Target rate limit + /// @dev Only contract owner can change this setting + /// @dev EVM selector for this function is: 0x77b6c908, + /// or in textual repr: setSponsoringRateLimit(address,uint32) + function setSponsoringRateLimit(address contractAddress, uint32 rateLimit) external; + + /// Set contract sponsoring fee limit + /// @dev Sponsoring fee limit - is maximum fee that could be spent by + /// single transaction + /// @param contractAddress Contract to change sponsoring fee limit of + /// @param feeLimit Fee limit + /// @dev Only contract owner can change this setting + /// @dev EVM selector for this function is: 0x03aed665, + /// or in textual repr: setSponsoringFeeLimit(address,uint256) + function setSponsoringFeeLimit(address contractAddress, uint256 feeLimit) external; + + /// Get current contract sponsoring fee limit + /// @param contractAddress Contract to get sponsoring fee limit of + /// @return uint256 Maximum amount of fee that could be spent by single + /// transaction + /// @dev EVM selector for this function is: 0x75b73606, + /// or in textual repr: sponsoringFeeLimit(address) + function sponsoringFeeLimit(address contractAddress) external view returns (uint256); + + /// Is specified user present in contract allow list + /// @dev Contract owner always implicitly included + /// @param contractAddress Contract to check allowlist of + /// @param user User to check + /// @return bool Is specified users exists in contract allowlist + /// @dev EVM selector for this function is: 0x5c658165, + /// or in textual repr: allowed(address,address) + function allowed(address contractAddress, address user) external view returns (bool); + + /// Toggle user presence in contract allowlist + /// @param contractAddress Contract to change allowlist of + /// @param user Which user presence should be toggled + /// @param isAllowed `true` if user should be allowed to be sponsored + /// or call this contract, `false` otherwise + /// @dev Only contract owner can change this setting + /// @dev EVM selector for this function is: 0x4706cc1c, + /// or in textual repr: toggleAllowed(address,address,bool) + function toggleAllowed( + address contractAddress, + address user, + bool isAllowed + ) external; + + /// Is this contract has allowlist access enabled + /// @dev Allowlist always can have users, and it is used for two purposes: + /// in case of allowlist sponsoring mode, users will be sponsored if they exist in allowlist + /// in case of allowlist access enabled, only users from allowlist may call this contract + /// @param contractAddress Contract to get allowlist access of + /// @return bool Is specified contract has allowlist access enabled + /// @dev EVM selector for this function is: 0xc772ef6c, + /// or in textual repr: allowlistEnabled(address) + function allowlistEnabled(address contractAddress) external view returns (bool); + + /// Toggle contract allowlist access + /// @param contractAddress Contract to change allowlist access of + /// @param enabled Should allowlist access to be enabled? + /// @dev EVM selector for this function is: 0x36de20f5, + /// or in textual repr: toggleAllowlist(address,bool) + function toggleAllowlist(address contractAddress, bool enabled) external; +} + +/// Available contract sponsoring modes +enum SponsoringModeT { + /// Sponsoring is disabled + Disabled, + /// Only users from allowlist will be sponsored + Allowlisted, + /// All users will be sponsored + Generous +} + +/// Optional value +struct OptionCrossAddress { + /// Shows the status of accessibility of value + bool status; + /// Actual value if `status` is true + CrossAddress value; +} + +/// Cross account struct +struct CrossAddress { + address eth; + uint256 sub; +} \ No newline at end of file diff --git a/docs/reference/blockchain/contract-helpers.md b/docs/reference/blockchain/contract-helpers.md new file mode 100644 index 0000000..dc1ace0 --- /dev/null +++ b/docs/reference/blockchain/contract-helpers.md @@ -0,0 +1,143 @@ +# Contract Helpers + +Address: **0x842899ecf380553e8a4de75bf534cdf6fbf64049** + +This precompiled contract allows the owner to manage the sponsorship of their contract. + +## Interface + +Below is an overview of the ContractHelpers API. + +--- + +
+ Click here to see the full interface + + @[code](./ContractHelpers.sol) +
+ +#### contractOwner + +*Returns the owner of the specified contract* +```solidity:no-line-numbers +function contractOwner(address contractAddress) public view returns (address) +``` + +#### setSponsor + +*Sets a sponsor for a specified contract* +```solidity:no-line-numbers +function setSponsor(address contractAddress, address sponsor) public +``` + +#### selfSponsoredEnable + +*Enables self-sponsorship for a specified contract* +```solidity:no-line-numbers +function selfSponsoredEnable(address contractAddress) public +``` + +#### removeSponsor + +*Removes the sponsor for a specified contract* +```solidity:no-line-numbers +function removeSponsor(address contractAddress) public +``` + +#### confirmSponsorship + +*Confirms sponsorship for a specified contract. The caller must be the same address that set the sponsor via setSponsor* +```solidity:no-line-numbers +function confirmSponsorship(address contractAddress) public +``` + +#### sponsor + +*Gets the current sponsor for a specified contract* +```solidity:no-line-numbers +function sponsor(address contractAddress) public view returns (OptionCrossAddress memory) +``` + +#### hasSponsor + +*Checks if a contract has a confirmed sponsor* +```solidity:no-line-numbers +function hasSponsor(address contractAddress) public view returns (bool) +``` + +#### hasPendingSponsor + +*Checks if a contract has a pending sponsor* +```solidity:no-line-numbers +function hasPendingSponsor(address contractAddress) public view returns (bool) +``` + +#### sponsoringEnabled + +*Checks if sponsoring is enabled for a specified contract* +```solidity:no-line-numbers +function sponsoringEnabled(address contractAddress) public view returns (bool) +``` + +#### setSponsoringMode + +*Sets the sponsoring mode for a specified contract* +```solidity:no-line-numbers +function setSponsoringMode(address contractAddress, SponsoringModeT mode) public +``` + +#### sponsoringRateLimit + +*Gets the current sponsoring rate limit for a specified contract* +```solidity:no-line-numbers +function sponsoringRateLimit(address contractAddress) public view returns (uint32) +``` + +#### setSponsoringRateLimit + +*Sets the sponsoring rate limit for a specified contract. Only the contract owner can change this setting* +```solidity:no-line-numbers +function setSponsoringRateLimit(address contractAddress, uint32 rateLimit) public +``` + +#### setSponsoringFeeLimit + +*Sets the sponsoring fee limit for a specified contract. Only the contract owner can change this setting* +```solidity:no-line-numbers +function setSponsoringFeeLimit(address contractAddress, uint256 feeLimit) public +``` + +#### sponsoringFeeLimit + +*Gets the current sponsoring fee limit for a specified contract* +```solidity:no-line-numbers +function sponsoringFeeLimit(address contractAddress) public view returns (uint256) +``` + +#### allowed + +*Checks if a specified user is present in the contract allowlist. The contract owner is always implicitly included* +```solidity:no-line-numbers +function allowed(address contractAddress, address user) public view returns (bool) +``` + +#### toggleAllowed + +*Toggles a user's presence in the contract allowlist. Only the contract owner can change this setting* +```solidity:no-line-numbers +function toggleAllowed(address contractAddress, address user, bool isAllowed) public +``` + +#### allowlistEnabled + +*Checks if allowlist access is enabled for a specified contract* +```solidity:no-line-numbers +function allowlistEnabled(address contractAddress) public view returns (bool) +``` + +#### toggleAllowlist + +*Toggles allowlist access for a specified contract. Only the contract owner can change this setting* +```solidity:no-line-numbers +function toggleAllowlist(address contractAddress, bool enabled) public +``` \ No newline at end of file