➡️Rewards

After a successful referral, Spindl will automatically credit wallets with rewards in an on-chain smart contract. The smart contract provides methods to directly to check the status of rewards for a particular wallet and facilitate a withdrawal transaction on-chain.

The Smart Contract address and Campaign ID to use in the methods below are specific to your running campaigns, and available within the Spindl Dashboard.

To test, you can use the 0xEC16738B5c89837e90f117dEAb1e9743Be562d69 on Arbitrum Goerli Test Net, with Campaign ID 1(details below).

All methods below are Smart Contract calls, that can be called via a library like Ethers.js

Check Available Rewards

RPC Call

getRecipient(_campaignId, _recpientAddress) public view returns (RecipientDetails memory) 

(Etherscan Reference)

Parameters

  • Campaign ID: This is the campaign id associated with the campaign you are running. If you are running multiple campaigns, you can check for rewards for each one individually.

  • Recipient Address: Logged in wallet.

Response

struct RecipientDetails {
    RecipientStatus status;
    uint256 earned;
    uint256 withdrawn;
}

enum RecipientStatus {
    NONE,
    ACTIVE,
    PAUSED
}

(Note: The status will almost always be NONE or ACTIVE. The PAUSED status is a special flag that only you can trigger, for suspicious referrers)

Examples

Wallet Has Pending Rewards

Recipient 0x0000000000000000000000000000000000000021 has been credited some rewards. The return value is:

[1,1200000000,0]

The status is ACTIVE (1), which means the recipient is eligible to withdraw funds. They have earned 1200000000 wei, and withdrawn 0 wei, so they are eligible to withdraw 1200000000 - 0 = 1200000000

Wallet Has No Rewards

Recipient 0x0000000000000000000000000000000000000000 has never been rewarded. The return value is:

[0, 0, 0]

The status is NONE (0), which means the recipient address has never been credited. The earned and withdrawn values are 0 (since there is nothing owed to them).

Wallet Has Withdrawn All Rewards

Recipient 0xD4ed4369ae2c27924ee59bd49459C642C20395B2 has withdrawn all rewards. In this case, the return value is:

[0,1200000000,1200000000]

The status is ACTIVE (1), which means the recipient is eligible to withdraw funds. They have earned 1200000000 wei, and withdrawn 1200000000 wei, so there are no remaining funds left to withdraw.

Withdraw Rewards

Transaction Call

withdrawRecipientEarnings(uint32 _campaignId, uint256 _amount, address _to) public virtual

(Etherscan Reference)

Parameters

  • Campaign ID: This is the campaign id associated with the campaign you are running.

  • Amount: The amount to withdraw. This is usually the total withdrawal amount, but can be a smaller amount as well. This will be in the currency for the campaign.

  • To: The recipient of the funds. This is usually the address of the wallet calling this function, but you can set it to another address specific by the user

Returns

This is a transaction, so there will be no return type. The transaction should be successful if the caller is owed at least that amount in the campaign.

Campaign Details

RPC Call

campaigns(_campaignId) public view returns (totalBudget uint256, status uint8, paymentType address, totalEarned uint256)

(Etherscan Reference)

Parameters

  • Campaign ID: This is the campaign id associated with the campaign you are running.

Returns

  • Total Budget: The total budget set by the owner of the campaign

  • Status

  • Payment Type: The ERC20 token, or 0x0... for the native currency

  • Total Earned: The total amount of token allocated referrers and referees.

Test Contract

Here is an example contract on the Arbitrum Tesnet:

  • Address: 0xEC16738B5c89837e90f117dEAb1e9743Be562d69 (URL)

  • Campaign ID: 1

We populated the campaign with earnings for these referrer addresses to make testing easier:

0xD4ed4369ae2c27924ee59bd49459C642C20395B2
0x0000000000000000000000000000000000000021
0x0000000000000000000000000000000000000022
0x0000000000000000000000000000000000000023
0x0000000000000000000000000000000000000024
0x0000000000000000000000000000000000000025
0x0000000000000000000000000000000000000026
0x0000000000000000000000000000000000000027
0x0000000000000000000000000000000000000028
0x0000000000000000000000000000000000000029
0x0000000000000000000000000000000000000030

Contract ABI

You can use this to interact with the contract with any Web3 client libraries, like Ethers.js

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadAddress","type":"error"},{"inputs":[],"name":"BadPayment","type":"error"},{"inputs":[],"name":"BadRequest","type":"error"},{"inputs":[],"name":"ImproperCampaignState","type":"error"},{"inputs":[],"name":"IncorrectAmount","type":"error"},{"inputs":[],"name":"OverAttributed","type":"error"},{"inputs":[],"name":"PaymentTypeDoesNotExist","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"campaignId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"withdrawAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalBalance","type":"uint256"}],"name":"BalanceWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"campaignId","type":"uint32"},{"indexed":false,"internalType":"address","name":"paymentType","type":"address"}],"name":"CampaignCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"campaignId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"updatedBudget","type":"uint256"}],"name":"CampaignFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"campaignId","type":"uint32"},{"indexed":false,"internalType":"enum PayoutVault.CampaignStatus","name":"oldState","type":"uint8"},{"indexed":false,"internalType":"enum PayoutVault.CampaignStatus","name":"newState","type":"uint8"}],"name":"CampaignStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"ManagerAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"paymentAddress","type":"address"}],"name":"PaymentAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"campaignId","type":"uint32"},{"indexed":false,"internalType":"address","name":"recipientAddress","type":"address"}],"name":"RecipientAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"campaignId","type":"uint32"},{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"enum PayoutVault.RecipientStatus","name":"status","type":"uint8"}],"name":"RecipientStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"campaignId","type":"uint32"},{"indexed":true,"internalType":"address","name":"recipientAddress","type":"address"},{"indexed":false,"internalType":"address","name":"paymentType","type":"address"},{"indexed":false,"internalType":"uint256","name":"newEarnings","type":"uint256"}],"name":"UpdateCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"campaignId","type":"uint32"},{"indexed":true,"internalType":"address","name":"recipientAddress","type":"address"},{"indexed":false,"internalType":"address","name":"paymentType","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalWithdrawn","type":"uint256"},{"indexed":false,"internalType":"enum PayoutVault.RecipientWithdrawType","name":"withdrawType","type":"uint8"}],"name":"WithdrawSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"WorkerAddressUpdated","type":"event"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"addERC20Payment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_campaignId","type":"uint32"},{"internalType":"address[]","name":"_recipientAddresses","type":"address[]"}],"name":"addRecipients","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"campaignCounter","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"campaigns","outputs":[{"internalType":"uint256","name":"totalBudget","type":"uint256"},{"internalType":"enum PayoutVault.CampaignStatus","name":"status","type":"uint8"},{"internalType":"address","name":"paymentType","type":"address"},{"internalType":"uint256","name":"totalEarned","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentType","type":"address"},{"internalType":"address[]","name":"_recipientAddresses","type":"address[]"}],"name":"createCampaign","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_campaignId","type":"uint32"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"fundCampaign","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_campaignId","type":"uint32"},{"internalType":"address","name":"_recipientAddress","type":"address"}],"name":"getRecipient","outputs":[{"components":[{"internalType":"enum PayoutVault.RecipientStatus","name":"status","type":"uint8"},{"internalType":"uint256","name":"earned","type":"uint256"},{"internalType":"uint256","name":"withdrawn","type":"uint256"}],"internalType":"struct PayoutVault.RecipientDetails","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_managerAddress","type":"address"},{"internalType":"address","name":"_workerAddress","type":"address"},{"internalType":"address[]","name":"_paymentTypes","type":"address[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"managerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"paymentTypes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_campaignId","type":"uint32"},{"internalType":"address[]","name":"_recipientAddresses","type":"address[]"}],"name":"pushRecipientEarnings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_campaignId","type":"uint32"},{"internalType":"enum PayoutVault.CampaignStatus","name":"_status","type":"uint8"}],"name":"setCampaignStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newAddress","type":"address"}],"name":"setManagerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_campaignId","type":"uint32"},{"internalType":"address","name":"_recipientAddress","type":"address"},{"internalType":"enum PayoutVault.RecipientStatus","name":"_status","type":"uint8"}],"name":"setRecipientStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newAddress","type":"address"}],"name":"setWorkerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"updateBalances","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"campaignId","type":"uint32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct PayoutVault.RecipientEarnings[]","name":"_campaigns","type":"tuple[]"},{"internalType":"address","name":"_to","type":"address"}],"name":"withdrawManyRecipientEarnings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_campaignId","type":"uint32"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"withdrawRecipientEarnings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_campaignId","type":"uint32"},{"internalType":"address","name":"_to","type":"address"}],"name":"withdrawRemainingCampaignBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"workerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

Last updated