This section provides an overview for developers interested in integrating their own dApps with DapDap. By focusing on usability, integration ease, and cross-chain functionality, developers can harness the full potential of NEAR JS to create open-source, connected, and streamlined applications for DapDap that can easily be hosted within the gateway.
DapDap Development Components
DapDap components offer a novel approach to creating web applications, combining the flexibility of composability with the decentralised nature NEAR Protocol. These components are intuitive for web developers, leveraging familiar concepts with a focus on efficiency and interaction with the underlying NEAR Tech Stack.
Leveraging NEAR Components
DapDap promotes the use of NEAR components, which are chain-agnostic and perfect for developing decentralised frontends. These components are designed to be composable, reusable, and decentralized, aligning with the ethos of open web development.
Why DapDap for Ethereum Developers?
DapDap represents an evolution in blockchain development platforms, offering:
A seamless transition for Ethereum developers with familiar tools and practices.
An opportunity to engage with a broader Ethereum ecosystem, encompassing all L2s and beyond.
A platform that values innovation, collaboration, and the democratisation of blockchain technology.
Key Features for Web Developers
Props and State Management: Utilise props for input and useState for state management, streamlining the development process.
Example:
Copy const name = props .name || "Maria" ;
const [ count , setCount ] = useState ( 1 );
return (
< div >
< p > {count} cheers for {name}! </ p >
< button onClick = {() => setCount (count + 1 )}>Cheers!</ button >
</ div >
);
Simplified Syntax: Unlike traditional frameworks, DapDap Components use NEAR JS to focus on the component's body, enhancing clarity and reducing boilerplate.
NEAR Native: Seamlessly integrate with NEAR smart contracts, differentiating between view
and call
methods for a direct interaction within your DapDap apps.
Example:
Copy const counter = Near .view ( 'counter.near-examples.testnet' , 'get_num' )
if (counter === null ) return 'Loading...'
const add = () => {
Near .call ( 'counter.near-examples.testnet' , 'increment' )
}
const subtract = () => {
Near .call ( 'counter.near-examples.testnet' , 'decrement' )
}
return <>
< p > Counter: {counter} </ p >
{ ! context .accountId &&
< p color = "red" > Please login to interact with the contract</ p >
}
{ context .accountId &&
<>
< button onClick = {add}> + </ button >
< button onClick = {subtract}> - </ button >
</>
}
</>
Multi-Chain Capabilities
Designed with cross-chain compatibility in mind, DapDap's NEAR JS components facilitate interaction across Ethereum and NEAR protocols, making multi-chain dApp development straightforward.
Copy if (
state .chainId === undefined &&
ethers !== undefined &&
Ethers .send ( "eth_requestAccounts" , [])[ 0 ]
) {
Ethers .provider ()
.getNetwork ()
.then ((chainIdData) => {
if ( chainIdData ?.chainId) {
State .update ({ chainId : chainIdData .chainId });
}
});
}
if ( state .chainId !== undefined && state .chainId !== 1 ) {
return < p >Switch to Ethereum Mainnet</ p >;
}
// FETCH LIDO ABI
const lidoContract = "0xae7ab96520de3a18e5e111b5eaab095312d7fe84" ;
const tokenDecimals = 18 ;
const lidoAbi = fetch (
"https://raw.githubusercontent.com/lidofinance/lido-subgraph/master/abis/Lido.json"
);
if ( ! lidoAbi .ok) {
return "Loading" ;
}
const iface = new ethers . utils .Interface ( lidoAbi .body);
// FETCH LIDO STAKING APR
if ( state .lidoArp === undefined ) {
const apr = fetch (
"https://api.allorigins.win/get?url=https://stake.lido.fi/api/sma-steth-apr"
);
if ( ! apr) return ;
State .update ({ lidoArp : JSON .parse ( apr ?. body ?.contents) ?? "..." });
}
// HELPER FUNCTIONS
const getStakedBalance = (receiver) => {
const encodedData = iface .encodeFunctionData ( "balanceOf" , [receiver]);
return Ethers .provider ()
.call ({
to : lidoContract ,
data : encodedData ,
})
.then ((rawBalance) => {
const receiverBalanceHex = iface .decodeFunctionResult (
"balanceOf" ,
rawBalance
);
return Big ( receiverBalanceHex .toString ())
.div ( Big ( 10 ) .pow (tokenDecimals))
.toFixed ( 2 )
.replace ( /\d(?=(\d {3} ) + \.)/ g , "$&," );
});
};
const submitEthers = (strEther , _referral) => {
if ( ! strEther) {
return console .log ( "Amount is missing" );
}
const erc20 = new ethers .Contract (
lidoContract ,
lidoAbi .body ,
Ethers .provider () .getSigner ()
);
let amount = ethers . utils .parseUnits (strEther , tokenDecimals) .toHexString ();
erc20 .submit (lidoContract , { value : amount }) .then ((transactionHash) => {
console .log ( "transactionHash is " + transactionHash);
});
};
// DETECT SENDER
if ( state .sender === undefined ) {
const accounts = Ethers .send ( "eth_requestAccounts" , []);
if ( accounts . length ) {
State .update ({ sender : accounts[ 0 ] });
console .log ( "set sender" , accounts[ 0 ]);
}
}
//if (!state.sender) return "Please login first";
// FETCH SENDER BALANCE
if ( state .balance === undefined && state .sender) {
Ethers .provider ()
.getBalance ( state .sender)
.then ((balance) => {
State .update ({ balance : Big (balance) .div ( Big ( 10 ) .pow ( 18 )) .toFixed ( 2 ) });
});
}
// FETCH SENDER STETH BALANCE
if ( state .stakedBalance === undefined && state .sender) {
getStakedBalance ( state .sender) .then ((stakedBalance) => {
State .update ({ stakedBalance });
});
}
// FETCH TX COST
if ( state .txCost === undefined ) {
const gasEstimate = ethers . BigNumber .from ( 1875000 );
const gasPrice = ethers . BigNumber .from ( 1500000000 );
const gasCostInWei = gasEstimate .mul (gasPrice);
const gasCostInEth = ethers . utils .formatEther (gasCostInWei);
let responseGql = fetch (
"https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2" ,
{
method : "POST" ,
headers : { "Content-Type" : "application/json" } ,
body : JSON .stringify ({
query : `{
bundle(id: "1" ) {
ethPrice
}
}` ,
}) ,
}
);
if ( ! responseGql) return "" ;
const ethPriceInUsd = responseGql . body . data . bundle .ethPrice;
const txCost = Number (gasCostInEth) * Number (ethPriceInUsd);
State .update ({ txCost : `$ ${ txCost .toFixed ( 2 ) } ` });
}
// FETCH CSS
const cssFont = fetch (
"https://fonts.googleapis.com/css2?family=Manrope:wght@200;300;400;500;600;700;800"
).body;
const css = fetch (
"https://pluminite.mypinata.cloud/ipfs/Qmboz8aoSvVXLeP5pZbRtNKtDD3kX5D9DEnfMn2ZGSJWtP"
).body;
if ( ! cssFont || ! css) return "" ;
if ( ! state .theme) {
State .update ({
theme : styled . div `
font-family: Manrope, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
${ cssFont }
${ css }
` ,
});
}
const Theme = state .theme;
// OUTPUT UI
const getSender = () => {
return ! state .sender
? ""
: state . sender .substring ( 0 , 6 ) +
"..." +
state . sender .substring ( state . sender . length - 4 , state . sender . length );
};
return (
< Theme >
< div className = "LidoContainer" >
< div className = "Header" >Stake Ether</ div >
< div className = "SubHeader" >Stake ETH and receive stETH while staking.</ div >
< div className = "LidoForm" >
{ state .sender && (
<>
< div className = "LidoFormTopContainer" >
< div className = "LidoFormTopContainerLeft" >
< div className = "LidoFormTopContainerLeftContent1" >
< div className = "LidoFormTopContainerLeftContent1Container" >
< span >Available to stake</ span >
< div className = "LidoFormTopContainerLeftContent1Circle" />
</ div >
</ div >
< div className = "LidoFormTopContainerLeftContent2" >
< span >
{ state .balance ?? ( ! state .sender ? "0" : "..." )} ETH
</ span >
</ div >
</ div >
< div className = "LidoFormTopContainerRight" >
< div className = "LidoFormTopContainerRightContent1" >
< div className = "LidoFormTopContainerRightContent1Text" >
< span >{ getSender ()}</ span >
</ div >
</ div >
</ div >
</ div >
< div className = "LidoSplitter" />
</>
)}
< div
className = {
state .sender ? "LidoFormBottomContainer" : "LidoFormTopContainer"
}
>
< div className = "LidoFormTopContainerLeft" >
< div className = "LidoFormTopContainerLeftContent1" >
< div className = "LidoFormTopContainerLeftContent1Container" >
< span >Staked amount</ span >
</ div >
</ div >
< div className = "LidoFormTopContainerLeftContent2" >
< span >
{ state .stakedBalance ?? ( ! state .sender ? "0" : "..." )}
stETH
</ span >
</ div >
</ div >
< div className = "LidoFormTopContainerRight" >
< div className = "LidoAprContainer" >
< div className = "LidoAprTitle" >Lido APR</ div >
< div className = "LidoAprValue" >{ state .lidoArp ?? "..." }%</ div >
</ div >
</ div >
</ div >
</ div >
< div className = "LidoStakeForm" >
< div className = "LidoStakeFormInputContainer" >
< span className = "LidoStakeFormInputContainerSpan1" >
< svg width = "24" height = "24" viewBox = "0 0 24 24" fill = "currentColor" >
< path
opacity = "0.6"
d = "M11.999 3.75v6.098l5.248 2.303-5.248-8.401z"
></ path >
< path d = "M11.999 3.75L6.75 12.151l5.249-2.303V3.75z" ></ path >
< path
opacity = "0.6"
d = "M11.999 16.103v4.143l5.251-7.135L12 16.103z"
></ path >
< path d = "M11.999 20.246v-4.144L6.75 13.111l5.249 7.135z" ></ path >
< path
opacity = "0.2"
d = "M11.999 15.144l5.248-2.993-5.248-2.301v5.294z"
></ path >
< path
opacity = "0.6"
d = "M6.75 12.151l5.249 2.993V9.85l-5.249 2.3z"
></ path >
</ svg >
</ span >
< span className = "LidoStakeFormInputContainerSpan2" >
< input
disabled = { ! state .sender}
className = "LidoStakeFormInputContainerSpan2Input"
value = { state .strEther}
onChange = {(e) => State .update ({ strEther : e . target .value })}
placeholder = "Amount"
/>
</ span >
< span
className = "LidoStakeFormInputContainerSpan3"
onClick = {() => {
State .update ({
strEther : ( state .balance > 0.05
? parseFloat ( state .balance) - 0.05
: 0
) .toFixed ( 2 ) ,
});
}}
>
< button
className = "LidoStakeFormInputContainerSpan3Content"
disabled = { ! state .sender}
>
< span className = "LidoStakeFormInputContainerSpan3Max" >MAX</ span >
</ button >
</ span >
</ div >
{ !! state .sender ? (
< button
className = "LidoStakeFormSubmitContainer"
onClick = {() => submitEthers ( state .strEther , state .sender)}
>
< span >Submit</ span >
</ button >
) : (
< Web3Connect
className = "LidoStakeFormSubmitContainer"
connectLabel = "Connect with Web3"
/>
)}
< div className = "LidoFooterContainer" >
{ state .sender && (
< div className = "LidoFooterRaw" >
< div className = "LidoFooterRawLeft" >You will receive</ div >
< div className = "LidoFooterRawRight" >${ state .strEther ?? 0 } stETH</ div >
</ div >
)}
< div className = "LidoFooterRaw" >
< div className = "LidoFooterRawLeft" >Exchange rate</ div >
< div className = "LidoFooterRawRight" >1 ETH = 1 stETH</ div >
</ div >
{ false && (
< div className = "LidoFooterRaw" >
< div className = "LidoFooterRawLeft" >Transaction cost</ div >
< div className = "LidoFooterRawRight" >{ state .txCost}</ div >
</ div >
)}
< div className = "LidoFooterRaw" >
< div className = "LidoFooterRawLeft" >Reward fee</ div >
< div className = "LidoFooterRawRight" >10%</ div >
</ div >
</ div >
</ div >
</ div >
</ Theme >
);
ETH Disabled in Docs For security reasons, interacting with Ethereum is disabled in our documentation. To see a working example please navigate to the deployed NEAR Component . :::
Getting Started
DapDap Components simplify the development process, allowing developers to focus on security, composability, and enhancing end user experience.
To begin developing DapDap Components, connect to NEAR JS and you can start creating decentralised, composable Open Web applications.
Last updated 5 months ago