SponsorWhitelistControl
Conflux实现了赞助机制,来补贴智能合约的使用。 这允许余额为零的新账户调用智能合约,前提是执行操作得到赞助(通常由Dapp运营者提供)。 内部的 SponsorWhitelistControl
合约记录了智能合约的赞助信息。
Interface
SponsorWhitelistControl's hex40 address is 0x0888000000000000000000000000000000000001
, with interface:
pragma solidity >=0.4.15;
contract SponsorWhitelistControl {
/*** Query Functions ***/
/**
* @dev get gas sponsor address of specific contract
* @param contractAddr The address of the sponsored contract
*/
function getSponsorForGas(address contractAddr) public view returns (address) {}
/**
* @dev get current Sponsored Balance for gas
* @param contractAddr The address of the sponsored contract
*/
function getSponsoredBalanceForGas(address contractAddr) public view returns (uint256) {}
/**
* @dev get current Sponsored Gas fee upper bound
* @param contractAddr The address of the sponsored contract
*/
function getSponsoredGasFeeUpperBound(address contractAddr) public view returns (uint256) {}
/**
* @dev get collateral sponsor address
* @param contractAddr The address of the sponsored contract
*/
function getSponsorForCollateral(address contractAddr) public view returns (address) {}
/**
* @dev get current Sponsored Balance for collateral
* @param contractAddr The address of the sponsored contract
*/
function getSponsoredBalanceForCollateral(address contractAddr) public view returns (uint256) {}
/**
* @dev check if a user is in a contract's whitelist
* @param contractAddr The address of the sponsored contract
* @param user The address of contract user
*/
function isWhitelisted(address contractAddr, address user) public view returns (bool) {}
/**
* @dev check if all users are in a contract's whitelist
* @param contractAddr The address of the sponsored contract
*/
function isAllWhitelisted(address contractAddr) public view returns (bool) {}
/*** for contract admin only **/
/**
* @dev contract admin add user to whitelist
* @param contractAddr The address of the sponsored contract
* @param addresses The user address array
*/
function addPrivilegeByAdmin(address contractAddr, address[] memory addresses) public {}
/**
* @dev contract admin remove user from whitelist
* @param contractAddr The address of the sponsored contract
* @param addresses The user address array
*/
function removePrivilegeByAdmin(address contractAddr, address[] memory addresses) public {}
// ------------------------------------------------------------------------
// Someone will sponsor the gas cost for contract `contractAddr` with an
// `upper_bound` for a single transaction.
// ------------------------------------------------------------------------
function setSponsorForGas(address contractAddr, uint upperBound) public payable {}
// ------------------------------------------------------------------------
// Someone will sponsor the storage collateral for contract `contractAddr`.
// ------------------------------------------------------------------------
function setSponsorForCollateral(address contractAddr) public payable {}
// ------------------------------------------------------------------------
// Add commission privilege for address `user` to some contract.
// ------------------------------------------------------------------------
function addPrivilege(address[] memory) public {}
// ------------------------------------------------------------------------
// Remove commission privilege for address `user` from some contract.
// ------------------------------------------------------------------------
function removePrivilege(address[] memory) public {}
/**
* @dev get current available storage points for collateral (activated after CIP-118)
* @param contractAddr The address of the sponsored contract
*/
function getAvailableStoragePoints(address contractAddr) public view returns (uint256) {}
}
如何赞助智能合约
SponsorWhitelistControl
为每个用户建立的合约维护一个白名单,包含有资格获得补贴的账户。 首先,应该使用 addPrivilege(address[] memory)
或 addPrivilegeByAdmin(address contractAddr, address[] memory addresses)
将合格账户添加到白名单中。 Specially, if a zero address is added to the whitelist, any account will become eligible for subsidy.
There are two resources that can be sponsored: gas consumption and storage collateral. 这两种资源可以通过 payable
接口 setSponsorForGas(address contractAddr, uint upperBound)
和 setSponsorForCollateral(address contractAddr)
分别进行赞助。
upperBound
(单位:Drip)设置了每笔交易的赞助上限。 交易发送的价值应不低于1000 * upperBound
。
示例
假定您有一个测试合约需要赞助:
pragma solidity >=0.8.0;
import "https://github.com/Conflux-Chain/conflux-rust/blob/master/internal_contract/contracts/SponsorWhitelistControl.sol";
contract CommissionPrivilegeTest {
mapping(uint => uint) public ss;
function add(address account) public {
SponsorWhitelistControl cpc = SponsorWhitelistControl(0x0888000000000000000000000000000000000001);
address[] memory a = new address[](1);
a[0] = account;
cpc.addPrivilege(a);
}
function remove(address account) public {
SponsorWhitelistControl cpc = SponsorWhitelistControl(0x0888000000000000000000000000000000000001);
address[] memory a = new address[](1);
a[0] = account;
cpc.removePrivilege(a);
}
function par_add(uint start, uint end) public {
for (uint i = start; i < end; i++) {
ss[i] = 1;
}
}
}
The following javascript code shows how to deploy and sponsor the provided test contract.
"use strict"
const { Conflux, Drip } = require("js-conflux-sdk")
// you need to change the path to the compiled contract
const { abi, bytecode } = require("path/to/CommissionPrivilegeTest.json");
async function main() {
// your secret key to deploy contract
// testnet token can be claimed at https://faucet.confluxnetwork.org/
const PRIVATE_KEY = '0x......';
const cfx = new Conflux({
url: 'https://test.confluxrpc.com',
// logger: console,
networkId: 1,
});
const account = cfx.wallet.addPrivateKey(PRIVATE_KEY); // create account instance
const randomAccount = cfx.wallet.addRandom() // a random account with no cfx
const testContract = cfx.Contract({
abi,
bytecode
})
const contract_addr = (await testContract.constructor().sendTransaction({
from: account.address
}).executed()).contractCreated
console.log(`contract deployed at ${contract_addr}`)
testContract.address = contract_addr
await testContract.add(randomAccount.address).sendTransaction({
from: account.address
}).executed()
console.log(`random address ${randomAccount.address} added to whitelist`)
const sponsor_contract = cfx.InternalContract('SponsorWhitelistControl');
const upperBound = 10n**15n
const upperBoundCfx = Drip(upperBound).toCFX()
const gasSponsorVal = 10n**18n
const storageSponsorVal = 10n ** 18n
if( gasSponsorVal < upperBound * 1000n ) {
throw new Error(`gas sponsor value should be greater than 1000 * upperBound`)
}
await sponsor_contract.setSponsorForGas(contract_addr, upperBound).sendTransaction({
from: account,
value: gasSponsorVal
}).executed();
console.log(`Gas is sponsored with upper bound ${upperBound} Drip (${upperBoundCfx} CFX)`)
await sponsor_contract.setSponsorForCollateral(contract_addr).sendTransaction({
from: account,
value: storageSponsorVal
}).executed();
console.log("Storage collateral is sponsored")
const receipt = await testContract.par_add(1, 3).sendTransaction({
from: randomAccount.address
}).executed()
console.log(`${receipt.transactionHash} is sent`)
console.log(`gas and storage covered by sponsor: ${receipt.gasCoveredBySponsor && receipt.storageCoveredBySponsor}`)
}
main().catch(
console.error
)
The example provided illustrates how to deploy and sponsor a test contract. The code is divided into five main sections:
- Setting Up Conflux Instance and Accounts
- Deploying the Smart Contract
- Interacting with the Deployed Contract
- Sponsoring Gas and Storage
- Sending a Transaction whose Gas and Storage are Sponsored
-
Setting Up Conflux Instance and Accounts:
const PRIVATE_KEY = '0x......';
const cfx = new Conflux({
url: 'https://test.confluxrpc.com',
networkId: 1,
});
const account = cfx.wallet.addPrivateKey(PRIVATE_KEY);
const randomAccount = cfx.wallet.addRandom();PRIVATE_KEY
: A placeholder for the private key of the user. This is essential for deploying contracts and sending transactions. You need to replace this value with your own private key with enough CFXaccount
: An account instance created using the provided private key. Will be used to deploy contract.randomAccount
: A new random account instance. This account doesn't have any CFX (Conflux's native currency) by default.
-
Deploying the Smart Contract:
const testContract = cfx.Contract({
abi,
bytecode
});
const contract_addr = (await testContract.constructor().sendTransaction({
from: account.address
}).executed()).contractCreated;
console.log(`contract deployed at ${contract_addr}`);testContract
: A new contract instance is created using the ABI and bytecode.
-
Interacting with the Deployed Contract:
testContract.address = contract_addr;
await testContract.add(randomAccount.address).sendTransaction({
from: account.address
}).executed();
console.log(`random address ${randomAccount.address} added to whitelist`);- The address of the deployed contract is set to the
testContract
instance. - A transaction is sent to the contract to add the random account's address to a whitelist.
- The address of the deployed contract is set to the
-
Sponsoring Gas and Storage:
const sponsor_contract = cfx.InternalContract('SponsorWhitelistControl');
const upperBound = 10n**15n;
const upperBoundCfx = Drip(upperbound).toCFX();
const gasSponsorVal = 10n**18n;
const storageSponsorVal = 10n ** 18n;
if( gasSponsorVal < upperBound * 1000n ) {
throw new Error(`gas sponsor value should be greater than 1000 * upperBound`);
}
await sponsor_contract.setSponsorForGas(contract_addr, upperBound).sendTransaction({
from: account,
value: gasSponsorVal
}).executed();
console.log(`Gas is sponsored with upper bound ${upperBound} Drip (${upperBoundCfx} CFX)`);
await sponsor_contract.setSponsorForCollateral(contract_addr).sendTransaction({
from: account,
value: storageSponsorVal
}).executed();
console.log("Storage collateral is sponsored");