Smart Contracts
Duty3 is composed of two factory contracts and vault contracts deployed per raffle. All contracts are verified on Arbiscan.
Contract Addresses (Arbitrum One)
Raffle Factory
Deploys new ERC-20 prize vaults. Entry point for createRaffle().
0x7CA34d13ca90A93B62E1cD515E236eDe7921c343
$DUTY3 Token
Native utility token. Hold 1,000+ for 10% ticket discount.
0x5C716a1194dE2dA092f0fd70dbF42843E8A3fbd3
Factory ABI (key functions)
// Create a new raffle vault
function createRaffle(
address _prizeToken, // WETH / WBTC / USDC address
uint256 _prizeAmount, // in token's native decimals
uint256 _ticketPrice, // base price per ticket
uint256 _maxTickets, // total ticket supply
uint256 _duration, // seconds from now
uint256 _winnerCount, // 1 for single winner
string _creatorTag // optional label, e.g. "AI"
) returns (address vault)
// Read vaults
function getRafflesPaginated(uint256 offset, uint256 limit)
view returns (address[])
function getRafflesCount() view returns (uint256)
function platformFeeBps() view returns (uint256)
function minPrizeAmount(address token) view returns (uint256)
function minTicketPrice(address token) view returns (uint256)
// Events
event RaffleCreated(
address indexed vault,
address indexed creator,
address prizeToken,
uint256 winnerCount
)Vault ABI (key functions)
// Participation
function buyTickets(uint256 _quantity)
function claimRefund()
// Pricing (respects DUTY3 discount)
function getPrice(address user) view returns (uint256)
// State
function state() view returns (uint8) // 0=OPEN, 1=CALCULATING, 2=COMPLETED, 3=REFUND
// Raffle info
function prizeToken() view returns (address)
function paymentToken() view returns (address)
function prizeAmount() view returns (uint256)
function baseTicketPrice() view returns (uint256)
function maxTickets() view returns (uint256)
function deadline() view returns (uint256)
function winnerCount() view returns (uint256)
function creator() view returns (address)
function creatorTag() view returns (string)
// Participation info
function getParticipantCount() view returns (uint256)
function getUserTicketIds(address user) view returns (uint256[])
function getSoldPercent() view returns (uint256)
function userSpent(address) view returns (uint256)
// Results
function getWinners() view returns (address[])
function getWinningTicketIds() view returns (uint256[])
// Events
event TicketBought(address indexed buyer, uint256 count, uint256[] ticketIds)
event WinnerPicked(address indexed winner, uint256 ticketId)
event MultiWinnersPicked(address[] winners, uint256[] ticketIds)
event StateChanged(uint8 indexed oldState, uint8 newState)Supported Tokens
| Token | Decimals | Address (Arbitrum) |
|---|---|---|
| WETH | 18 | 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1 |
| WBTC | 8 | 0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f |
| USDC | 6 | 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 |
Integration Example (ethers v6)
import { ethers } from "ethers"
const FACTORY = "0x7CA34d13ca90A93B62E1cD515E236eDe7921c343"
const FACTORY_ABI = [
"function createRaffle(address,uint256,uint256,uint256,uint256,uint256,string) returns (address)",
"function getRafflesPaginated(uint256,uint256) view returns (address[])",
]
const VAULT_ABI = [
"function buyTickets(uint256)",
"function getPrice(address) view returns (uint256)",
"function state() view returns (uint8)",
]
const provider = new ethers.JsonRpcProvider("https://arb1.arbitrum.io/rpc")
const signer = new ethers.Wallet(PRIVATE_KEY, provider)
const factory = new ethers.Contract(FACTORY, FACTORY_ABI, signer)
// Get all vaults
const vaults = await factory.getRafflesPaginated(0n, 50n)
// Buy a ticket
const vault = new ethers.Contract(vaults[0], VAULT_ABI, signer)
const price = await vault.getPrice(signer.address)
// Approve WETH first, then:
await vault.buyTickets(1n)