Baadhi ya mbinu zinazotumiwa na tokeni za utapeli na jinsi ya kuzigundua
Katika mafunzo haya tunachambua tokeni ya utapeli (opens in a new tab) ili kuona baadhi ya mbinu ambazo matapeli hutumia na jinsi wanavyozitekeleza. Kufikia mwisho wa mafunzo haya utakuwa na mtazamo mpana zaidi wa mikataba ya tokeni za ERC-20, uwezo wake, na kwa nini kuwa na shaka ni muhimu. Kisha tunaangalia matukio yanayotolewa na tokeni hiyo ya utapeli na kuona jinsi tunavyoweza kutambua kuwa si halali kiotomatiki.
Tokeni za utapeli - ni nini, kwa nini watu wanazitengeneza, na jinsi ya kuziepuka
Moja ya matumizi ya kawaida ya Ethereum ni kwa kikundi kuunda tokeni inayoweza kuuzwa, kwa maana fulani sarafu yao wenyewe. Hata hivyo, popote pale ambapo kuna matumizi halali yanayoleta thamani, pia kuna wahalifu wanaojaribu kujiibia thamani hiyo.
Unaweza kusoma zaidi kuhusu mada hii kwingineko kwenye ethereum.org kutoka kwa mtazamo wa mtumiaji. Mafunzo haya yanalenga katika kuchambua tokeni ya utapeli ili kuona jinsi inavyofanywa na jinsi inavyoweza kugunduliwa.
Ninajuaje kuwa wARB ni utapeli?
Tokeni tunayochambua ni wARB (opens in a new tab), ambayo inajifanya kuwa sawa na tokeni halali ya ARB (opens in a new tab).
Njia rahisi zaidi ya kujua ni tokeni ipi iliyo halali ni kuangalia shirika lililoianzisha, Arbitrum (opens in a new tab). Anwani halali zimebainishwa katika nyaraka zao (opens in a new tab).
Kwa nini msimbo wa chanzo unapatikana?
Kwa kawaida tungetarajia watu wanaojaribu kutapeli wengine kuwa wasiri, na kwa kweli tokeni nyingi za utapeli hazina msimbo wao unaopatikana (kwa mfano, hii hapa (opens in a new tab) na hii hapa (opens in a new tab)).
Hata hivyo, tokeni halali kwa kawaida huchapisha msimbo wao wa chanzo, kwa hivyo ili kuonekana halali waandishi wa tokeni za utapeli wakati mwingine hufanya vivyo hivyo. wARB (opens in a new tab) ni mojawapo ya tokeni hizo zenye msimbo wa chanzo unaopatikana, jambo ambalo hurahisisha kuielewa.
Ingawa wasambazaji wa mkataba wanaweza kuchagua kuchapisha au kutochapisha msimbo wa chanzo, hawawezi kuchapisha msimbo wa chanzo usio sahihi. Kichunguzi cha bloku hukusanya msimbo wa chanzo uliotolewa kwa kujitegemea, na ikiwa hakipati msimbo wa baiti sawa kabisa, kinakataa msimbo huo wa chanzo. Unaweza kusoma zaidi kuhusu hili kwenye tovuti ya Etherscan (opens in a new tab).
Ulinganisho na tokeni halali za ERC-20
Tutalinganisha tokeni hii na tokeni halali za ERC-20. Ikiwa hufahamu jinsi tokeni halali za ERC-20 zinavyoandikwa kwa kawaida, tazama mafunzo haya.
Vigezo visivyobadilika kwa anwani zenye mapendeleo
Mikataba wakati mwingine inahitaji anwani zenye mapendeleo. Mikataba iliyoundwa kwa matumizi ya muda mrefu inaruhusu anwani fulani yenye mapendeleo kubadilisha anwani hizo, kwa mfano kuwezesha matumizi ya mkataba mpya wa saini-nyingi. Kuna njia kadhaa za kufanya hivi.
Mkataba wa tokeni wa HOP (opens in a new tab) unatumia muundo wa Ownable (opens in a new tab). Anwani yenye mapendeleo huwekwa kwenye hifadhi, katika sehemu inayoitwa _owner (tazama faili la tatu, Ownable.sol).
abstract contract Ownable is Context {
address private _owner;
.
.
.
}
Mkataba wa tokeni wa ARB (opens in a new tab) hauna anwani yenye mapendeleo moja kwa moja. Hata hivyo, hauhitaji moja. Unakaa nyuma ya proxy (opens in a new tab) kwenye anwani 0xb50721bcf8d664c30412cfbc6cf7a15145234ad1 (opens in a new tab). Mkataba huo una anwani yenye mapendeleo (tazama faili la nne, ERC1967Upgrade.sol) inayoweza kutumika kwa uboreshaji.
/**
* @dev Inahifadhi anwani mpya katika sloti ya msimamizi ya EIP1967.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
Kinyume chake, mkataba wa wARB una contract_owner iliyowekwa moja kwa moja kwenye msimbo.
contract WrappedArbitrum is Context, IERC20 {
.
.
.
address deployer = 0xB50721BCf8d664c30412Cfbc6cf7a15145234ad1;
address public contract_owner = 0xb40dE7b1beE84Ff2dc22B70a049A07A13a411A33;
.
.
.
}
Mmiliki huyu wa mkataba (opens in a new tab) si mkataba unaoweza kudhibitiwa na akaunti tofauti kwa nyakati tofauti, bali ni akaunti inayomilikiwa na mtu wa nje. Hii inamaanisha kuwa huenda imeundwa kwa matumizi ya muda mfupi na mtu binafsi, badala ya kuwa suluhisho la muda mrefu la kudhibiti ERC-20 itakayosalia kuwa na thamani.
Na kwa kweli, tukitazama kwenye Etherscan tunaona kwamba tapeli alitumia mkataba huu kwa saa 12 pekee (muamala wa kwanza (opens in a new tab) hadi muamala wa mwisho (opens in a new tab)) mnamo Mei 19, 2023.
Kazi feki ya _transfer
Ni kawaida kuwa na mahamisho halisi yakifanyika kwa kutumia kazi ya ndani ya _transfer.
Katika wARB kazi hii inaonekana karibu halali:
function _transfer(address sender, address recipient, uint256 amount) internal virtual{
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
if (sender == contract_owner){
sender = deployer;
}
emit Transfer(sender, recipient, amount);
}
Sehemu inayotia shaka ni:
if (sender == contract_owner){
sender = deployer;
}
emit Transfer(sender, recipient, amount);
Ikiwa mmiliki wa mkataba anatuma tokeni, kwa nini tukio la Transfer linaonyesha zinatoka kwa deployer?
Hata hivyo, kuna suala muhimu zaidi. Nani anaita kazi hii ya _transfer? Haiwezi kuitwa kutoka nje, imewekwa alama ya internal. Na msimbo tulio nao haujumuishi miito yoyote kwa _transfer. Ni wazi, iko hapa kama chambo.
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_f_(_msgSender(), recipient, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_f_(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
Tunapoangalia kazi zinazoitwa kuhamisha tokeni, transfer na transferFrom, tunaona kwamba zinaita kazi tofauti kabisa, _f_.
Kazi halisi ya _f_
function _f_(address sender, address recipient, uint256 amount) internal _mod_(sender,recipient,amount) virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
if (sender == contract_owner){
sender = deployer;
}
emit Transfer(sender, recipient, amount);
}
Kuna viashiria viwili vinavyowezekana vya hatari katika kazi hii.
-
Matumizi ya kirekebishaji cha kazi (opens in a new tab)
_mod_. Hata hivyo, tunapoangalia ndani ya msimbo wa chanzo tunaona kwamba_mod_kwa kweli haina madhara.modifier _mod_(address sender, address recipient, uint256 amount){ _; } -
Suala lile lile tuliloona katika
_transfer, ambalo ni wakaticontract_ownerinatuma tokeni zinaonekana kutoka kwadeployer.
Kazi feki ya matukio dropNewTokens
Sasa tunakuja kwenye kitu kinachoonekana kama utapeli halisi. Nilihariri kazi hii kidogo ili isomeke kwa urahisi, lakini inafanya kazi sawa.
function dropNewTokens(address uPool,
address[] memory eReceiver,
uint256[] memory eAmounts) public auth()
Kazi hii ina kirekebishaji cha auth(), ambayo inamaanisha inaweza kuitwa tu na mmiliki wa mkataba.
modifier auth() {
require(msg.sender == contract_owner, "Not allowed to interact");
_;
}
Kizuizi hiki kinaleta maana kabisa, kwa sababu hatungetaka akaunti za kubahatisha zisambaze tokeni. Hata hivyo, sehemu iliyosalia ya kazi inatia shaka.
{
for (uint256 i = 0; i < eReceiver.length; i++) {
emit Transfer(uPool, eReceiver[i], eAmounts[i]);
}
}
Kazi ya kuhamisha kutoka kwa akaunti ya pamoja hadi kwa orodha ya wapokeaji orodha ya kiasi inaleta maana kabisa. Kuna matumizi mengi ambapo utataka kusambaza tokeni kutoka chanzo kimoja hadi maeneo mengi, kama vile malipo ya mishahara, airdrops, n.k. Ni nafuu (kwa gesi) kufanya katika muamala mmoja badala ya kutoa miamala mingi, au hata kuita ERC-20 mara nyingi kutoka kwa mkataba tofauti kama sehemu ya muamala huo huo.
Hata hivyo, dropNewTokens haifanyi hivyo. Inatoa matukio ya Transfer (opens in a new tab), lakini kwa kweli haihamishi tokeni zozote. Hakuna sababu halali ya kuchanganya programu za nje ya mnyororo kwa kuziambia kuhusu hamisho ambalo halikufanyika kweli.
Kazi ya kuteketeza ya Approve
Mikataba ya ERC-20 inapaswa kuwa na kazi ya approve kwa ajili ya vibali, na kwa kweli tokeni yetu ya utapeli ina kazi kama hiyo, na hata ni sahihi. Hata hivyo, kwa sababu Solidity inatokana na C inajali herufi kubwa na ndogo. "Approve" na "approve" ni mifuatano tofauti.
Pia, utendaji hauhusiani na approve.
function Approve(
address[] memory holders)
Kazi hii inaitwa na orodha ya anwani za wamiliki wa tokeni.
public approver() {
Kirekebishaji cha approver() kinahakikisha kuwa contract_owner pekee ndiye anayeruhusiwa kuita kazi hii (tazama hapa chini).
for (uint256 i = 0; i < holders.length; i++) {
uint256 amount = _balances[holders[i]];
_beforeTokenTransfer(holders[i], 0x0000000000000000000000000000000000000001, amount);
_balances[holders[i]] = _balances[holders[i]].sub(amount,
"ERC20: burn amount exceeds balance");
_balances[0x0000000000000000000000000000000000000001] =
_balances[0x0000000000000000000000000000000000000001].add(amount);
}
}
Kwa kila anwani ya mmiliki kazi inahamisha salio lote la mmiliki hadi kwenye anwani 0x00...01, na kuiteketeza kikamilifu (burn halisi katika kiwango pia inabadilisha usambazaji wa jumla, na kuhamisha tokeni hadi 0x00...00). Hii inamaanisha kuwa contract_owner inaweza kuondoa mali za mtumiaji yeyote. Hicho hakionekani kama kipengele ambacho ungetaka katika tokini ya utawala.
Masuala ya ubora wa msimbo
Masuala haya ya ubora wa msimbo hayathibitishi kwamba msimbo huu ni utapeli, lakini yanafanya uonekane wa kutiliwa shaka. Kampuni zilizopangwa vizuri kama vile Arbitrum kwa kawaida hazitoi msimbo mbaya kiasi hiki.
Kazi ya mount
Ingawa haijabainishwa katika kiwango (opens in a new tab), kwa ujumla kazi inayounda tokeni mpya inaitwa mint.
Tukiangalia katika konstrukta ya wARB, tunaona kazi ya kufua muda imebadilishwa jina kuwa mount kwa sababu fulani, na inaitwa mara tano na sehemu ya tano ya usambazaji wa awali, badala ya mara moja kwa kiasi chote kwa ufanisi.
constructor () public {
_name = "Wrapped Arbitrum";
_symbol = "wARB";
_decimals = 18;
uint256 initialSupply = 1000000000000;
mount(deployer, initialSupply*(10**18)/5);
mount(deployer, initialSupply*(10**18)/5);
mount(deployer, initialSupply*(10**18)/5);
mount(deployer, initialSupply*(10**18)/5);
mount(deployer, initialSupply*(10**18)/5);
}
Kazi ya mount yenyewe pia inatia shaka.
function mount(address account, uint256 amount) public {
require(msg.sender == contract_owner, "ERC20: mint to the zero address");
Tukiangalia require, tunaona kwamba mmiliki wa mkataba pekee ndiye anayeruhusiwa kufua. Hiyo ni halali. Lakini ujumbe wa kosa unapaswa kuwa only owner is allowed to mint au kitu kama hicho. Badala yake, ni ujumbe usiohusika wa ERC20: mint to the zero address. Jaribio sahihi la kufua kwenye anwani sifuri ni require(account != address(0), "<error message>"), ambalo mkataba haujisumbui kuliangalia.
_totalSupply = _totalSupply.add(amount);
_balances[contract_owner] = _balances[contract_owner].add(amount);
emit Transfer(address(0), account, amount);
}
Kuna mambo mawili zaidi yanayotia shaka, yanayohusiana moja kwa moja na ufuzi:
-
Kuna kigezo cha
account, ambacho huenda ni akaunti inayopaswa kupokea kiasi kilichofuliwa. Lakini salio linaloongezeka kwa kweli ni lacontract_owner. -
Ingawa salio lililoongezeka ni la
contract_owner, tukio lililotolewa linaonyesha hamisho kwenda kwaaccount.
Kwa nini zote mbili auth na approver? Kwa nini mod ambayo haifanyi chochote?
Mkataba huu una virekebishaji vitatu: _mod_, auth, na approver.
modifier _mod_(address sender, address recipient, uint256 amount){
_;
}
_mod_ inachukua vigezo vitatu na haifanyi chochote navyo. Kwa nini iwe nayo?
modifier auth() {
require(msg.sender == contract_owner, "Not allowed to interact");
_;
}
modifier approver() {
require(msg.sender == contract_owner, "Not allowed to interact");
_;
}
auth na approver zinaleta maana zaidi, kwa sababu zinaangalia kwamba mkataba uliitwa na contract_owner. Tungetarajia vitendo fulani vyenye mapendeleo, kama vile ufuzi, viwe na kikomo kwa akaunti hiyo. Hata hivyo, kuna maana gani ya kuwa na kazi mbili tofauti zinazofanya kitu kile kile haswa?
Tunaweza kugundua nini kiotomatiki?
Tunaweza kuona kwamba wARB ni tokeni ya utapeli kwa kuangalia Etherscan. Hata hivyo, hilo ni suluhisho lililowekwa kati. Kinadharia, Etherscan inaweza kuhujumiwa au kudukuliwa. Ni bora kuweza kujua kwa kujitegemea ikiwa tokeni ni halali au la.
Kuna baadhi ya mbinu tunazoweza kutumia kutambua kwamba tokeni ya ERC-20 inatia shaka (iwe ni utapeli au imeandikwa vibaya sana), kwa kuangalia matukio inayotoa.
Matukio ya Approval yanayotia shaka
Matukio ya Approval (opens in a new tab) yanapaswa kutokea tu kwa ombi la moja kwa moja (tofauti na matukio ya Transfer (opens in a new tab) ambayo yanaweza kutokea kama matokeo ya kibali). Tazama nyaraka za Solidity (opens in a new tab) kwa maelezo ya kina ya suala hili na kwa nini maombi yanahitaji kuwa ya moja kwa moja, badala ya kupatanishwa na mkataba.
Hii inamaanisha kuwa matukio ya Approval yanayoidhinisha matumizi kutoka kwa akaunti inayomilikiwa na mtu wa nje lazima yatokane na miamala inayoanzia kwenye akaunti hiyo, na ambayo lengo lake ni mkataba wa ERC-20. Aina nyingine yoyote ya idhini kutoka kwa akaunti inayomilikiwa na mtu wa nje inatia shaka.
Hapa kuna programu inayotambua aina hii ya tukio (opens in a new tab), kwa kutumia Viem (opens in a new tab) na TypeScript (opens in a new tab), lahaja ya JavaScript yenye usalama wa aina. Ili kuiendesha:
- Nakili
.env.examplehadi.env. - Hariri
.envili kutoa URL kwa nodi ya Mtandao Mkuu wa Ethereum. - Endesha
pnpm installili kusakinisha vifurushi vinavyohitajika. - Endesha
pnpm susApprovalili kutafuta idhini zinazotia shaka.
Hapa kuna maelezo ya mstari kwa mstari:
import {
Address,
TransactionReceipt,
createPublicClient,
http,
parseAbiItem,
} from "viem"
import { mainnet } from "viem/chains"
Ingiza ufafanuzi wa aina, kazi, na ufafanuzi wa mnyororo kutoka viem.
import { config } from "dotenv"
config()
Soma .env ili kupata URL.
const client = createPublicClient({
chain: mainnet,
transport: http(process.env.URL),
})
Unda mteja wa Viem. Tunahitaji tu kusoma kutoka kwenye mnyororo wa vitalu, kwa hivyo mteja huyu hahitaji ufunguo wa siri.
const testedAddress = "0xb047c8032b99841713b8e3872f06cf32beb27b82"
const fromBlock = 16859812n
const toBlock = 16873372n
Anwani ya mkataba wa ERC-20 unaotia shaka, na bloku ambazo ndani yake tutatafuta matukio. Watoa huduma wa nodi kwa kawaida huweka kikomo uwezo wetu wa kusoma matukio kwa sababu kipimo data kinaweza kuwa ghali. Kwa bahati nzuri wARB haikutumika kwa kipindi cha saa kumi na nane, kwa hivyo tunaweza kutafuta matukio yote (kulikuwa na 13 pekee kwa jumla).
const approvalEvents = await client.getLogs({
address: testedAddress,
fromBlock,
toBlock,
event: parseAbiItem(
"event Approval(address indexed _owner, address indexed _spender, uint256 _value)"
),
})
Hii ndiyo njia ya kuuliza Viem taarifa za tukio. Tunapoipatia sahihi kamili ya tukio, ikijumuisha majina ya sehemu, inachanganua tukio kwa ajili yetu.
const isContract = async (addr: Address): boolean =>
await client.getBytecode({ address: addr })
Kanuni yetu inatumika tu kwa akaunti zinazomilikiwa na watu wa nje. Ikiwa kuna msimbo wa baiti wowote uliorejeshwa na client.getBytecode inamaanisha kuwa huu ni mkataba na tunapaswa kuuruka tu.
Ikiwa hujawahi kutumia TypeScript hapo awali, ufafanuzi wa kazi unaweza kuonekana wa kushangaza kidogo. Hatuiambii tu kigezo cha kwanza (na cha pekee) kinaitwa addr, lakini pia kwamba ni cha aina ya Address. Vile vile, sehemu ya : boolean inaiambia TypeScript kwamba thamani ya kurejesha ya kazi ni boolean.
const getEventTxn = async (ev: Event): TransactionReceipt =>
await client.getTransactionReceipt({ hash: ev.transactionHash })
Kazi hii inapata stakabadhi ya muamala kutoka kwa tukio. Tunahitaji stakabadhi ili kuhakikisha tunajua lengo la muamala lilikuwa nini.
const suspiciousApprovalEvent = async (ev : Event) : (Event | null) => {
Hii ndiyo kazi muhimu zaidi, ile inayoamua kwa kweli ikiwa tukio linatia shaka au la. Aina ya kurejesha, (Event | null), inaiambia TypeScript kwamba kazi hii inaweza kurejesha ama Event au null. Tunarejesha null ikiwa tukio halitii shaka.
const owner = ev.args._owner
Viem ina majina ya sehemu, kwa hivyo ilichanganua tukio kwa ajili yetu. _owner ni mmiliki wa tokeni zitakazotumika.
// Vibali vya mikataba havitiliwi shaka
if (await isContract(owner)) return null
Ikiwa mmiliki ni mkataba, chukulia idhini hii haitii shaka. Ili kuangalia ikiwa idhini ya mkataba inatia shaka au la tutahitaji kufuatilia utekelezaji kamili wa muamala ili kuona ikiwa uliwahi kufika kwenye mkataba wa mmiliki, na ikiwa mkataba huo uliita mkataba wa ERC-20 moja kwa moja. Hiyo inagharimu rasilimali nyingi zaidi kuliko tunavyopenda kufanya.
const txn = await getEventTxn(ev)
Ikiwa idhini inatoka kwa akaunti inayomilikiwa na mtu wa nje, pata muamala uliosababisha.
// Kibali kinatiliwa shaka kama kinatoka kwa mmiliki wa EOA ambaye si `from` ya muamala
if (owner.toLowerCase() != txn.from.toLowerCase()) return ev
Hatuwezi tu kuangalia usawa wa mfuatano kwa sababu anwani ni heksadesimali, kwa hivyo zina herufi. Wakati mwingine, kwa mfano katika txn.from, herufi hizo zote ni ndogo. Katika hali nyingine, kama vile ev.args._owner, anwani iko katika herufi mchanganyiko kwa utambuzi wa makosa (opens in a new tab).
Lakini ikiwa muamala hautoki kwa mmiliki, na mmiliki huyo anamilikiwa na mtu wa nje, basi tuna muamala unaotia shaka.
// Pia inatiliwa shaka kama lengwa la muamala si mkataba wa ERC-20 ambao
// tunauchunguza
if (txn.to.toLowerCase() != testedAddress) return ev
Vile vile, ikiwa anwani ya to ya muamala, mkataba wa kwanza ulioitwa, si mkataba wa ERC-20 unaochunguzwa basi inatia shaka.
// Kama hakuna sababu ya kutilia shaka, rejesha null.
return null
}
Ikiwa hakuna sharti lililo la kweli basi tukio la Approval halitii shaka.
const testPromises = approvalEvents.map((ev) => suspiciousApprovalEvent(ev))
const testResults = (await Promise.all(testPromises)).filter((x) => x != null)
console.log(testResults)
Kazi ya async (opens in a new tab) inarejesha kipengee cha Promise. Kwa sintaksia ya kawaida, await x(), tunasubiri Promise hiyo itimizwe kabla ya kuendelea na uchakataji. Hii ni rahisi kupanga na kufuata, lakini pia haina ufanisi. Wakati tunasubiri Promise kwa tukio maalum kutimizwa tunaweza tayari kuanza kufanyia kazi tukio linalofuata.
Hapa tunatumia map (opens in a new tab) kuunda orodha ya vipengee vya Promise. Kisha tunatumia Promise.all (opens in a new tab) kusubiri ahadi hizo zote kutatuliwa. Kisha tunachuja (filter (opens in a new tab)) matokeo hayo ili kuondoa matukio yasiyotia shaka.
Matukio ya Transfer yanayotia shaka
Njia nyingine inayowezekana ya kutambua tokeni za utapeli ni kuona ikiwa zina mahamisho yoyote yanayotia shaka. Kwa mfano, mahamisho kutoka kwa akaunti ambazo hazina tokeni nyingi hivyo. Unaweza kuona jinsi ya kutekeleza jaribio hili (opens in a new tab), lakini wARB haina suala hili.
Hitimisho
Ugunduzi wa kiotomatiki wa utapeli wa ERC-20 unakabiliwa na matokeo hasi ya uongo (opens in a new tab), kwa sababu utapeli unaweza kutumia mkataba wa tokeni wa ERC-20 wa kawaida kabisa ambao hauwakilishi chochote halisi. Kwa hivyo unapaswa kujaribu kila wakati kupata anwani ya tokeni kutoka kwa chanzo kinachoaminika.
Ugunduzi wa kiotomatiki unaweza kusaidia katika hali fulani, kama vile vipande vya fedha zilizogatuliwa (DeFi), ambapo kuna tokeni nyingi na zinahitaji kushughulikiwa kiotomatiki. Lakini kama kawaida mnunuzi achukue tahadhari (caveat emptor) (opens in a new tab), fanya utafiti wako mwenyewe, na uwahimize watumiaji wako kufanya vivyo hivyo.
Tazama hapa kwa kazi zangu zaidi (opens in a new tab).
Ukurasa ulisasishwa mwisho: 3 Aprili 2026