Skip to main content
updated answer with another solution
Source Link

UPDATE 2022

Time passes, experience is added ;)

You can use signed messages. Have a look at this contract: https://etherscan.io/address/0xF2Bce1776A49250A5cad0F81aeb5C21Be72F537a#code

On line 374 (File 1 of 21):

function mintById_SignedMessage(uint256 _tokenId, uint256 _setPrice, uint256 expirationTimestamp, uint256 _nonce, bytes memory _sig) public payable{
        // check validity and execute
        require(expirationTimestamp <= block.timestamp, "Expired");
        bytes32 message = SignedMessages.prefixed(keccak256(abi.encodePacked(msg.sender, _tokenId, _setPrice, expirationTimestamp, _nonce)));
        require(msg.value == _setPrice, "Wrong payment");
        require(SignedMessages.consumePass(message, _sig, _nonce), "Error in signed msg");
        _internalMintById(msg.sender, _tokenId);
        if (msg.value > 0) {
            emit FundsReceived(msg.sender, msg.value, "payment by minting sale");
        }
    }

This function is called by passing so called "minting passes". Head down to file 3 of 21: This is the contract that checks the signature. So, the call parameters get signed with the private key of a valid "issuer" offchain (by you). Then you provide this signed message to the users (e.g. via frontend or backend) and when they call the contract, they can provide that signed message. Your contract can verify it has been issued by the right issuer, as shown here:

function consumePass(bytes32 message, bytes memory sig, uint256 nonce) internal returns(bool){
    // check the nonce first
    if (nonces[nonce]) {
        return false;
    }
    // check the issuer
    if (!issuers[recoverSigner(message, sig)]) {
        return false;
    }
    // consume the nonce if it is safe
    nonces[nonce] = true;
    return true;
}

Some further links:

UPDATE 2022

Time passes, experience is added ;)

You can use signed messages. Have a look at this contract: https://etherscan.io/address/0xF2Bce1776A49250A5cad0F81aeb5C21Be72F537a#code

On line 374 (File 1 of 21):

function mintById_SignedMessage(uint256 _tokenId, uint256 _setPrice, uint256 expirationTimestamp, uint256 _nonce, bytes memory _sig) public payable{
        // check validity and execute
        require(expirationTimestamp <= block.timestamp, "Expired");
        bytes32 message = SignedMessages.prefixed(keccak256(abi.encodePacked(msg.sender, _tokenId, _setPrice, expirationTimestamp, _nonce)));
        require(msg.value == _setPrice, "Wrong payment");
        require(SignedMessages.consumePass(message, _sig, _nonce), "Error in signed msg");
        _internalMintById(msg.sender, _tokenId);
        if (msg.value > 0) {
            emit FundsReceived(msg.sender, msg.value, "payment by minting sale");
        }
    }

This function is called by passing so called "minting passes". Head down to file 3 of 21: This is the contract that checks the signature. So, the call parameters get signed with the private key of a valid "issuer" offchain (by you). Then you provide this signed message to the users (e.g. via frontend or backend) and when they call the contract, they can provide that signed message. Your contract can verify it has been issued by the right issuer, as shown here:

function consumePass(bytes32 message, bytes memory sig, uint256 nonce) internal returns(bool){
    // check the nonce first
    if (nonces[nonce]) {
        return false;
    }
    // check the issuer
    if (!issuers[recoverSigner(message, sig)]) {
        return false;
    }
    // consume the nonce if it is safe
    nonces[nonce] = true;
    return true;
}

Some further links:

Add formatting for future viewers
Source Link
Shane Fontaine
  • 18.3k
  • 20
  • 56
  • 83

So, you will need to write your own "Oracle". Your offchain application can gather the addresses, and an administrative backend, where only you have access, could be used to call a "registerOwners"registerOwners function in the contract, that adds the address to a list of owners (be sure to provide a way of also deactivating them, if needed).

This should be tested, but in order to save gas, you could have your friends call a function that saves their address in a mapping (a kind of pre-registration), and you would just call a function that flips a boolean inside of a struct, saying that the pre-registration has been allowed.

So, you will need to write your own "Oracle". Your offchain application can gather the addresses, and an administrative backend, where only you have access, could be used to call a "registerOwners" function in the contract, that adds the address to a list of owners (be sure to provide a way of also deactivating them, if needed).

This should be tested, but in order to save gas, you could have your friends call a function that saves their address in a mapping (a kind of pre-registration), and you would just call a function that flips a boolean inside of a struct, saying that the pre-registration has been allowed.

So, you will need to write your own "Oracle". Your offchain application can gather the addresses, and an administrative backend, where only you have access, could be used to call a registerOwners function in the contract, that adds the address to a list of owners (be sure to provide a way of also deactivating them, if needed).

This should be tested, but in order to save gas, you could have your friends call a function that saves their address in a mapping (a kind of pre-registration), and you would just call a function that flips a boolean inside of a struct, saying that the pre-registration has been allowed.

fixing grammar
Source Link

So, you will need to write your own "Oracle". Your offchain application can gather the addresses, and an administrative backend, where only you have access, could be used to call a "registerOwners" function in the contract, that adds the address to a list of owners (be sure to provide a way of also deactivating them, if needed).

This should be tested, but in order to save gas, you could have your friends call a function that saves their address in a mapping (a kind of pre-registration), and you would just call a function that flips a boolean inside of a struct, saying that the pre-registration has been allowed.

So you will need to write your own "Oracle". Your offchain application can gather the addresses, and an administrative backend, where only you have access, could be used to call a "registerOwners" function in the contract, that adds the address to a list of owners (be sure to provide a way of also deactivating them if needed).

This should be tested, but in order to save gas, you could have your friends call a function that saves their address in a mapping (a kind of pre-registration), and you would just call a function that flips a boolean inside of a struct saying that the pre-registration has been allowed.

So, you will need to write your own "Oracle". Your offchain application can gather the addresses, and an administrative backend, where only you have access, could be used to call a "registerOwners" function in the contract, that adds the address to a list of owners (be sure to provide a way of also deactivating them, if needed).

This should be tested, but in order to save gas, you could have your friends call a function that saves their address in a mapping (a kind of pre-registration), and you would just call a function that flips a boolean inside of a struct, saying that the pre-registration has been allowed.

Source Link
Loading