reef-defi / reef-chain

EVM compatible chain with NPoS/PoC consensus
https://docs.reef.io
GNU General Public License v3.0
135 stars 37 forks source link

Unable to interact with smart contract #44

Closed 4skinSkywalker closed 3 years ago

4skinSkywalker commented 3 years ago

I'm trying to complete the integration with Reef on our dapp, currently testing a contract in the Reef Testenet but I kept getting Error: call revert exception.

image

So far I'm able to connect to Polkadot{.js} and successfully get the account address, provider and signer. I can instantiate the contract with ethers without errors but as soon as I call contract's methods I get errors.

The contract deployment can be found at https://testnet.reefscan.com/block/?blockNumber=889100.

I paste here the dapp contract addresses and ABI:

export let ETHBOX = {
    ADDRESSES: {
        ETHEREUM: "0x501AC1D6103fB2643f2cB93985baAac6f81d1Bc9",
        ETHEREUM_TESTNET: "0xAAa491Cf3cA23D59a77eB56Ab487169F4B49e4e2",
        BINANCE: "0x98F8E39032B4dBEC2235B68Bd7CC2505D3793161",
        BINANCE_TESTNET: "0xF559344bF9A51bF778fB0Ff38cc690bAF7E61081",
        MATIC: "0xbD1E729074A14348c78E39b56992f54f0b5d37Ec",
        MATIC_TESTNET: "0x6c1cd6434B5Ee4A75605981387cBb3cdDc5596d0",
        REEF_TESTNET: "0x33bead687546ba417c170c0523155b2dcf45106b"
    },
    ABI: [{"inputs":[{"internalType":"uint256","name":"_boxIndex","type":"uint256"}],"name":"cancelBox","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_boxIndex","type":"uint256"}],"name":"cancelBoxWithPrivacy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_boxIndex","type":"uint256"},{"internalType":"bytes32","name":"_passHash","type":"bytes32"}],"name":"clearBox","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_boxIndex","type":"uint256"},{"internalType":"bytes32","name":"_passHash","type":"bytes32"}],"name":"clearBoxWithPrivacy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"contract ERC20Interface","name":"_sendToken","type":"address"},{"internalType":"uint256","name":"_sendValue","type":"uint256"},{"internalType":"contract ERC20Interface","name":"_requestToken","type":"address"},{"internalType":"uint256","name":"_requestValue","type":"uint256"},{"internalType":"bytes32","name":"_passHashHash","type":"bytes32"}],"name":"createBox","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_recipientHash","type":"bytes32"},{"internalType":"contract ERC20Interface","name":"_sendToken","type":"address"},{"internalType":"uint256","name":"_sendValue","type":"uint256"},{"internalType":"bytes32","name":"_passHashHash","type":"bytes32"}],"name":"createBoxWithPrivacy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundAllBoxes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_state","type":"bool"}],"name":"setStopDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"uint256","name":"_boxIndex","type":"uint256"}],"name":"getBox","outputs":[{"components":[{"internalType":"address payable","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes32","name":"passHashHash","type":"bytes32"},{"internalType":"contract ERC20Interface","name":"sendToken","type":"address"},{"internalType":"uint256","name":"sendValue","type":"uint256"},{"internalType":"contract ERC20Interface","name":"requestToken","type":"address"},{"internalType":"uint256","name":"requestValue","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"taken","type":"bool"}],"internalType":"struct ethbox.Box","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBoxesAll","outputs":[{"components":[{"internalType":"address payable","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes32","name":"passHashHash","type":"bytes32"},{"internalType":"contract ERC20Interface","name":"sendToken","type":"address"},{"internalType":"uint256","name":"sendValue","type":"uint256"},{"internalType":"contract ERC20Interface","name":"requestToken","type":"address"},{"internalType":"uint256","name":"requestValue","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"taken","type":"bool"}],"internalType":"struct ethbox.Box[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBoxesAllWithPrivacy","outputs":[{"components":[{"internalType":"bytes32","name":"senderHash","type":"bytes32"},{"internalType":"bytes32","name":"recipientHash","type":"bytes32"},{"internalType":"bytes32","name":"passHashHash","type":"bytes32"},{"internalType":"contract ERC20Interface","name":"sendToken","type":"address"},{"internalType":"uint256","name":"sendValue","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"taken","type":"bool"}],"internalType":"struct ethbox.BoxWithPrivacy[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBoxesIncoming","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBoxesIncomingWithPrivacy","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBoxesOutgoing","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBoxesOutgoingWithPrivacy","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_boxIndex","type":"uint256"}],"name":"getBoxWithPrivacy","outputs":[{"components":[{"internalType":"bytes32","name":"senderHash","type":"bytes32"},{"internalType":"bytes32","name":"recipientHash","type":"bytes32"},{"internalType":"bytes32","name":"passHashHash","type":"bytes32"},{"internalType":"contract ERC20Interface","name":"sendToken","type":"address"},{"internalType":"uint256","name":"sendValue","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"taken","type":"bool"}],"internalType":"struct ethbox.BoxWithPrivacy","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumBoxes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumBoxesWithPrivacy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
};

I paste some code below, let me know if there's something I'm missing:

let connection = await this.web3Modal.connect();

// When user has tapped on Reef, initialize things differently
if (connection.custom && /reef/.test(connection.custom)) {

    this.isReef$.next(true);

    // Either "reeftestnet" or "reefmainnet"
    this.reefCustomProviderName = connection.custom;

    this.loadingIndicatorServ.on();

    let WS_URL = this.isReefTestnet() ?
        "wss://rpc-testnet.reefscan.com/ws" :
        "wss://rpc.reefscan.com/ws";

    // Return an array of all the injected sources
    // (this needs to be called first)
    const allInjected = await web3Enable('ethbox dapp');
    console.log("All injected", allInjected);

    let signer;
    if (allInjected[0] && allInjected[0].signer) {
        signer = allInjected[0].signer;
    }

    // Return an array of { address, meta: { name, source } }
    // (meta.source contains the name of the extension)
    const allAccounts = await web3Accounts();
    console.log("All accounts", allAccounts);

    if (allAccounts[0] && allAccounts[0].address) {
        this.selectedAccount$.next(allAccounts[0].address);
    }

    if (!this.selectedAccount$.getValue()) {
        this.loadingIndicatorServ.off();
        return;
    }

    this.provider = new Provider({
        provider: new WsProvider(WS_URL)
    });
    console.log("Provider", this.provider);

    await this.provider.api.isReady;

    this.signer = new Signer(
        this.provider,
        this.selectedAccount$.getValue(),
        signer
    );
    console.log("Signer", this.signer);

    this.loadingIndicatorServ.off();
}

[...]

// The following code sets contracts depending on the current chain
switch(chainId) {
    case 13939: // Reef
        if (this.isReefTestnet()) {
            this.ethboxAddress = ETHBOX.ADDRESSES.REEF_TESTNET;
        } else {
            this.hardReset();
            this.loadingIndicatorServ.off();
            return;
        }
        break;
    case 1:     // Ethereum Mainnet
        this.isEthereumMainnet$.next(true);
        this.ethboxAddress = ETHBOX.ADDRESSES.ETHEREUM;
        this.stakingAddress = STAKING.ADDRESSES.ETHEREUM;
        break;
    case 4:     // Ethereum Testnet
        this.ethboxAddress = ETHBOX.ADDRESSES.ETHEREUM_TESTNET; 
        this.tokenDispenserAddress = TOKEN_DISPENSER.ADDRESSES.ETHEREUM_TESTNET;
        break;
    [...other chains here...]

if (this.ethboxAddress) {
    this.ethboxContract = new ethers.Contract(
        this.ethboxAddress,
        ETHBOX.ABI,
        this.signer
    );
}

This exact code works flawlessly on every chain except Reef. Maybe something went wrong during the contract deployment?

Thanks, Fredo

4skinSkywalker commented 3 years ago

OK guys, I got to the root of this: I had no EVM address paired with my Polkadot generated SR25519 address.

Now one thing: how do I get the EVM address when connected with polkadot{.js}?

Normally I would do the following:

// Retrieving the selectedAccount
let accounts = await this.provider.listAccounts();
console.log("Accounts", accounts);

this.selectedAccount$.next(accounts[0]);

But I see this is returning an error as there's no listAccounts method in your provider... How to go on with this?

Post Scriptum

I've found a couple of methods inside the signer module: image

Yet when I await both it stays pending... :/

Maybe it's because I keep getting disconnected from the WS: image

How do I solve this?

Post Post Scriptum

I confirm that I was unable to get the pending promises resolved because of frequent disconnections.

Is it possible to listen for a disconnection event?

Thanks

Netherdrake commented 3 years ago

The public RPC might be overloaded, hence Abnormal closure. Best to run your own node if you want to make many connections.

As you may have noticed, Reef is not like Ethereum, because it is not based on Ethereum. So its unlikely things will work with your existing web3 provider. You will probably want to check out reef provider https://docs.reef.finance/docs/developers/js_libraries/

Lastly, it might be expedient for you to borrow code from UI examples or one of the OS projects: https://github.com/reef-defi/ui-examples https://github.com/reef-defi/reefswap

Netherdrake commented 3 years ago

The call issue on testnet is confirmed, we are working on a fix.

You can use the mainnet in the meantime.

Netherdrake commented 3 years ago

The testnet has been upgraded to v7.

https://github.com/reef-defi/reef-chain/releases/tag/v7

The smart contracts deployed on testnet from block 1,077,077 to 1,145,000 have been lost. Any smart contracts affected by address overwriting will have to be redeployed as well.