QX ERC20 วิทยาศาสตร์วิทยาศาสตร์ /** *ส่งเพื่อตรวจสอบที่ etherscan.io เมื่อวันที่ 2020-12-24 * / /
Pragma Solidity ^0.6.0;
-
@DEV wrappers ผ่านการดำเนินการทางคณิตศาสตร์ของ Solidity พร้อมกับเพิ่มล้น
ตรวจสอบ
การดำเนินการทางคณิตศาสตร์ในความแข็งแกร่งห่อหุ้มล้น ซึ่งสามารถส่งผลได้อย่างง่ายดาย
ในข้อบกพร่องเพราะโปรแกรมเมอร์มักจะคิดว่าการล้น
ข้อผิดพลาดซึ่งเป็นพฤติกรรมมาตรฐานในภาษาการเขียนโปรแกรมระดับสูง
SafeMath เรียกคืนสัญชาตญาณนี้โดยการคืนธุรกรรมเมื่อ
การดำเนินการล้น
การใช้ไลบรารีนี้แทนการดำเนินการที่ไม่ได้ตรวจสอบจะช่วยลดทั้งหมด
ชั้นเรียนของข้อบกพร่องดังนั้นจึงแนะนำให้ใช้เสมอ / ห้องสมุด safemath { / *
@DEV ส่งคืนการเพิ่มจำนวนเต็มสองอันที่ไม่ได้ลงชื่อคืน
ล้น
คู่กับตัวดำเนินการ + ของ Solidity
ความต้องการ:
กลับ C; -
-
--
@dev ส่งคืนการลบของจำนวนเต็มสองตัวที่ไม่ได้ลงนามคืนด้วยข้อความที่กำหนดเอง
ล้น (เมื่อผลลัพธ์เป็นลบ)
คู่กับผู้ดำเนินการ -
ความต้องการ:
กลับ C; -
-
@dev ส่งคืนการคูณของจำนวนเต็มสองตัวที่ไม่ได้ลงชื่อคืน
ล้น
คู่กับผู้ให้บริการ * ของ Solidity
ความต้องการ:
UINT256 C = A * B; ต้องการ (c / a == b, "Safemath: การคูณล้น");
กลับ C; -
-
/ ผู้ประกอบการ หมายเหตุ: ฟังก์ชั่นนี้ใช้ไฟล์revert opcode (ซึ่งทิ้งก๊าซที่เหลืออยู่) ในขณะที่ความแข็งแกร่ง-
@DEV ส่งคืนการแบ่งจำนวนเต็มของจำนวนเต็มที่ไม่ได้ลงนามสองครั้ง ส่งกลับด้วยข้อความที่กำหนดเองบน
ส่วนโดยศูนย์ ผลลัพธ์จะถูกปัดเป็นศูนย์
คู่กับความแข็งแกร่ง / ผู้ประกอบการ หมายเหตุ: ฟังก์ชั่นนี้ใช้ไฟล์
revert opcode (ซึ่งทิ้งก๊าซที่เหลืออยู่) ในขณะที่ความแข็งแกร่ง
ใช้ opcode ที่ไม่ถูกต้องเพื่อเปลี่ยนกลับ (บริโภคก๊าซที่เหลือทั้งหมด)
ความต้องการ:
กลับ C; -
-
% ของ Solidity ฟังก์ชั่นนี้ใช้ revert-
% ของ Solidity ฟังก์ชั่นนี้ใช้ revert// ใบอนุญาตบางส่วน: MIT
Pragma Solidity ^0.6.0;
-
@DEV ยูทิลิตี้คณิตศาสตร์มาตรฐานที่ขาดหายไปในภาษาที่แข็งแกร่ง / คณิตศาสตร์ห้องสมุด { / *
-
-
// ใบอนุญาตบางส่วน: MIT
Pragma Solidity ^0.6.0;
-
@dev ค้นหา array ที่เรียงลำดับและส่งคืนดัชนีแรกที่มี
ค่ามากกว่าหรือเท่ากับ element หากไม่มีดัชนีดังกล่าว (เช่นทั้งหมด
ค่าในอาร์เรย์น้อยกว่า element อย่างเคร่งครัด) ความยาวของอาร์เรย์คือ
กลับมา ความซับซ้อนของเวลา o (log n)
array คาดว่าจะจัดเรียงตามลำดับจากน้อยไปหามากขึ้นและมี NO
องค์ประกอบซ้ำ ๆ */ ฟังก์ชั่น findupperbound (uint256 [] อาร์เรย์หน่วยเก็บข้อมูล, องค์ประกอบ UINT256) การส่งคืนมุมมองภายใน (uint256) {ถ้า (array.length == 0) {return 0; -
UINT256 ต่ำ = 0; uint256 สูง = array.length;
ในขณะที่ (ต่ำ <สูง) {uint256 mid = math.average (ต่ำ, สูง);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds down (it does integer division with truncation).
if (array[mid] > element) {
high = mid;
} else {
low = mid + 1;
}
-
// ณ จุดนี้ low คือขอบเขตบนสุดพิเศษ เราจะส่งคืนขอบเขตบนแบบรวม ถ้า (ต่ำ> 0 && อาร์เรย์ [ต่ำ - 1] == องค์ประกอบ) {return low - 1; } else {return low; -
// ใบอนุญาตบางส่วน: MIT
Pragma Solidity ^0.6.0;
-
@title เคาน์เตอร์
@author Matt Condon (@shrugs)
@DEV จัดเตรียมเคาน์เตอร์ที่สามารถเพิ่มหรือลดลงได้โดยหนึ่ง สามารถใช้งานได้เช่นเพื่อติดตามหมายเลข
ขององค์ประกอบในการทำแผนที่การออก ERC721 ID หรือการนับรหัสคำขอ
รวมกับ using Counters for Counters.Counter;
เนื่องจากเป็นไปไม่ได้ที่จะล้นจำนวนเต็ม 256 บิตโดยเพิ่มขึ้นหนึ่ง increment สามารถข้าม {safemath}
ตรวจสอบล้นดังนั้นจึงช่วยประหยัดก๊าซ สิ่งนี้ถือว่าถูกต้องอย่างไรก็ตามการใช้งานที่ _value ไม่เคยมีมาก่อน
เข้าถึงได้โดยตรง */ เคาน์เตอร์ห้องสมุด {ใช้ Safemath สำหรับ UINT256;
ตัวนับโครงสร้าง {// ตัวแปรนี้ไม่ควรเข้าถึงได้โดยตรงโดยผู้ใช้ไลบรารี: การโต้ตอบจะต้องถูก จำกัด ให้ // ฟังก์ชั่นของไลบรารี ในฐานะที่เป็นความแข็งแกร่ง v0.5.2 สิ่งนี้ไม่สามารถบังคับใช้ได้แม้ว่าจะมีข้อเสนอที่จะเพิ่ม // คุณสมบัตินี้: ดู Ethereum/Solidity#4637 UINT256 _Value; // ค่าเริ่มต้น: 0}
ฟังก์ชั่นปัจจุบัน (ตัวนับตัวนับตัวนับ) การส่งคืนมุมมองภายใน (UINT256) {return counter._value; -
ฟังก์ชั่นเพิ่มขึ้น (ตัวนับตัวนับตัวนับ) ภายใน {// {safemath} การตรวจสอบล้นสามารถข้ามได้ที่นี่ดูความคิดเห็นที่ตัวนับด้านบน _Value += 1; -
ฟังก์ชั่นการลดลง (ตัวนับตัวนับตัวนับ) ภายใน {counter._value = counter._value.sub (1); -
// ใบอนุญาตบางส่วน: MIT
Pragma Solidity ^0.6.0;
-
@DEV ให้ข้อมูลเกี่ยวกับบริบทการดำเนินการปัจจุบันรวมถึงไฟล์
ผู้ส่งธุรกรรมและข้อมูล ในขณะที่สิ่งเหล่านี้มีอยู่โดยทั่วไป
ผ่าน msg.sender และ msg.data พวกเขาไม่ควรเข้าถึงในโดยตรงดังกล่าว
ลักษณะตั้งแต่เมื่อต้องรับมือกับการทำธุรกรรม GSN meta การส่งบัญชีและ
การจ่ายเงินสำหรับการดำเนินการอาจไม่ใช่ผู้ส่งจริง (เท่าที่แอปพลิเคชัน
เป็นห่วง)
สัญญานี้เป็นสิ่งจำเป็นสำหรับสัญญาระดับกลางที่เหมือนห้องสมุดเท่านั้น */ บริบทสัญญานามธรรม {ฟังก์ชั่น _MSGSENDER () การส่งคืน VINTULANT VIENT (ที่อยู่ที่ต้องชำระ) {return msg.sender; -
ฟังก์ชั่น _MSGDATA () มุมมองภายในการส่งคืนเสมือน (หน่วยความจำไบต์) {สิ่งนี้; // Silence State Mutability คำเตือนโดยไม่ต้องสร้าง bytecode - ดู Ethereum/Solidity#2691 return msg.data; -
// ใบอนุญาตบางส่วน: MIT
Pragma Solidity ^0.6.0;
-
@DEV อินเทอร์เฟซของมาตรฐาน ERC20 ตามที่กำหนดไว้ใน EIP / อินเทอร์เฟซ IERC20 { / *
-
account */ ฟังก์ชั่นยอดคงเหลือ (บัญชีที่อยู่) การส่งคืนมุมมองภายนอก (UINT256);-
amount โทเค็นจากบัญชีของผู้โทรไปยัง recipient-
spender จะเป็นowner ผ่าน {transferfrom} นี่คือ-
amount เป็นค่าเผื่อของ spender เหนือโทเค็นของผู้โทร-
amount โทเค็นจาก sender ไปยัง recipient โดยใช้ไฟล์amount จะถูกหักออกจากผู้โทร-
value ถูกย้ายจากบัญชีหนึ่ง ( from ) ไปเป็นto )value อาจเป็นศูนย์ */ การถ่ายโอนเหตุการณ์ (ที่อยู่ดัชนีจากที่อยู่ดัชนีไปยังค่า UINT256);-
spender สำหรับ owner ถูกกำหนดโดยvalue เป็นค่าเผื่อใหม่ */ การอนุมัติเหตุการณ์ (ที่อยู่ดัชนีเจ้าของ, ที่อยู่ดัชนี Spender, ค่า UINT256); -// ใบอนุญาตบางส่วน: MIT
Pragma Solidity ^0.6.2;
-
@DEV คอลเลกชันของฟังก์ชั่นที่เกี่ยวข้องกับที่อยู่ประเภท / ที่อยู่ไลบรารี { / *
@DEV ส่งคืนจริงถ้า account เป็นสัญญา
[สำคัญ]
-
ไม่ปลอดภัยที่จะสมมติว่าที่อยู่ที่ฟังก์ชั่นนี้ส่งคืน
FALSE เป็นบัญชีภายนอก (EOA) และไม่ใช่สัญญา
ในหมู่คนอื่น ๆ isContract จะกลับมาเป็นเท็จสำหรับสิ่งต่อไปนี้
ประเภทของที่อยู่:
==== */ ฟังก์ชั่น isContract (บัญชีที่อยู่) การส่งคืนมุมมองภายใน (BOOL) {// วิธีนี้อาศัย ExtCodeSize ซึ่งส่งคืน 0 สำหรับสัญญาใน // การก่อสร้างเนื่องจากรหัสจะถูกเก็บไว้ในตอนท้ายของ // Constructor
ขนาด uint256; // Solhint-disable-next-line แอสเซมบลี assembly {size: = extCodeSize (บัญชี)} ขนาดส่งคืน> 0; -
-
@DEV ทดแทนสำหรับ transfer ของ Solidity: ส่ง amount WEI ไปที่
recipient การส่งต่อก๊าซที่มีอยู่ทั้งหมดและคืนข้อผิดพลาด
https://eips.ethereum.org/eips/EIP-1884 RODEIP1884] เพิ่มต้นทุนก๊าซ
ของ opcodes บางอย่างอาจทำสัญญาได้เกินขีด จำกัด ของก๊าซ 2300
กำหนดโดย transfer ทำให้พวกเขาไม่สามารถรับเงินผ่านได้
transfer . {sendValue} ลบข้อ จำกัด นี้
https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/
สำคัญ: เนื่องจากการควบคุมถูกโอนไปยัง recipient การดูแลต้องเป็น
นำมาเพื่อไม่สร้างช่องโหว่ใหม่ พิจารณาใช้
{reentrancyguard} หรือ
https://solidity.readthedocs.io/en/v0.5.11/security-consomrations.html#use-the-checks-effects-interactions-pattern [รูปแบบ effects-interactions] */ ฟังก์ชั่น sendValue (ที่อยู่ผู้รับที่ต้องชำระเงิน, UINT256 จำนวน) ภายใน {ต้องการ (ที่อยู่ (ที่อยู่ (นี้). Balance> = จำนวนเงิน "ที่อยู่: ยอดคงเหลือไม่เพียงพอ");
// solhint-disable-next-line หลีกเลี่ยงระดับต่ำ-ระดับโทร, หลีกเลี่ยงการเรียกเก็บเงิน (ความสำเร็จบูล,) = ผู้รับ. call {ค่า: จำนวน} (""); ต้องการ (ความสำเร็จ "ที่อยู่: ไม่สามารถส่งค่าผู้รับอาจกลับมาอีก"); -
-
call ระดับต่ำ อันcall ธรรมดาเป็นการแทนที่ที่ไม่ปลอดภัยสำหรับการโทรฟังก์ชั่น: ใช้สิ่งนี้target กลับมาอีกครั้งด้วยเหตุผลที่กลับมาอีกtarget จะต้องเป็นสัญญาtarget ด้วย data จะต้องไม่กลับ-
functionCall ] แต่กับerrorMessage เป็นเหตุผลย้อนกลับทางเลือกเมื่อ target กลับมาอีกครั้ง-
functionCall ]value WEI ไปยัง targetvalue ETH อย่างน้อยที่สุดpayable-
functionCallWithValue ] แต่errorMessage เป็นเหตุผลย้อนกลับทางเลือกเมื่อ target กลับมาอีกครั้งฟังก์ชั่น _functionCallWithValue (เป้าหมายที่อยู่, ข้อมูลหน่วยความจำไบต์, UINT256 Weivalue, String Memory ErrorMessage) การส่งคืนส่วนตัว (หน่วยความจำไบต์) {ต้องการ (isContract (เป้าหมาย), "ที่อยู่: เรียกไปที่ไม่ใช่สัญญา");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
-
// ใบอนุญาตบางส่วน: MIT
Pragma Solidity ^0.6.0;
-
@DEV การใช้งานอินเตอร์เฟส {IERC20}
การใช้งานนี้ไม่เชื่อเรื่องพระเจ้ากับวิธีการสร้างโทเค็น หมายถึง
จะต้องเพิ่มกลไกการจัดหาในสัญญาที่ได้รับโดยใช้ {_mint}
สำหรับกลไกทั่วไปโปรดดู {ERC20PRESETMInterpauser}
เคล็ดลับ: สำหรับการเขียนโดยละเอียดดูคำแนะนำของเรา
https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226 Hhow
เพื่อใช้กลไกการจัดหา]
เราได้ปฏิบัติตามแนวทางทั่วไปของ Openzeppelin: ฟังก์ชั่นเปลี่ยนกลับแทน
ของการกลับมา false เมื่อความล้มเหลว พฤติกรรมนี้เป็นเรื่องธรรมดา
และไม่ขัดแย้งกับความคาดหวังของแอปพลิเคชัน ERC20
นอกจากนี้เหตุการณ์ {การอนุมัติ} ถูกปล่อยออกมาจากการโทรไปยัง {transferfrom}
สิ่งนี้ช่วยให้แอปพลิเคชันสามารถสร้างค่าเผื่อสำหรับบัญชีทั้งหมดได้ใหม่
โดยการฟังเหตุการณ์ดังกล่าว การใช้งานอื่น ๆ ของ EIP อาจไม่ปล่อยออกมา
เหตุการณ์เหล่านี้ตามข้อกำหนดไม่จำเป็น
ในที่สุด {decreaseAllowance} และ {upereAllowance}}
มีการเพิ่มฟังก์ชั่นเพื่อลดปัญหาที่รู้จักกันดีเกี่ยวกับการตั้งค่า
เบี้ยเลี้ยง ดู {ierc20-Approve} */ สัญญา ERC20 เป็นบริบท, IERC20 {การใช้ SafEmath สำหรับ UINT256; ใช้ที่อยู่สำหรับที่อยู่
การแม็พ (ที่อยู่ => uint256) ส่วนตัว _balances;
การแม็พ (ที่อยู่ => การแมป (ที่อยู่ => uint256)) ส่วนตัว _allowances;
UINT256 ส่วนตัว _totalsUpply;
สตริงส่วนตัว _name; สตริงส่วนตัว _symbol; Uint8 ส่วนตัว _decimals;
-
-
-
-
decimals เท่ากับ 2 ความสมดุลของโทเค็น 505 ควร5,05 ( 505 / 10 ** 2 )-
-
-
recipient ไม่สามารถเป็นที่อยู่เป็นศูนย์ได้amount */ ฟังก์ชั่นการถ่ายโอน (ผู้รับที่อยู่, จำนวน UINT256) ผลตอบแทนการแทนที่เสมือนจริงสาธารณะ (บูล) {_Transfer (_MSGSENDER (), ผู้รับ, จำนวน); กลับมาจริง; --
-
spender ไม่สามารถเป็นที่อยู่เป็นศูนย์ได้ */ ฟังก์ชั่นอนุมัติ (ที่อยู่ Spender, UINT256 จำนวนเงิน) ผลตอบแทนการแทนที่เสมือนจริงสาธารณะ (บูล) {_Approve (_MSGSENDER (), เครื่องเทศ, จำนวนเงิน); กลับมาจริง; --
sender และ recipient ไม่สามารถเป็นที่อยู่เป็นศูนย์ได้sender จะต้องมียอดคงเหลืออย่างน้อย amountsender อย่างน้อยamount . */ function transferfrom (ผู้ส่งที่อยู่ผู้รับที่อยู่, UINT256 จำนวน) การแทนที่เสมือนจริงกลับ (BOOL) {_Transfer (ผู้ส่ง, ผู้รับ, จำนวน); _Approve (ผู้ส่ง, _MSGSENDER (), _ALLANCENS [ผู้ส่ง] [_ MSGSENDER ()]. ย่อย (จำนวนเงิน, "ERC20: จำนวนการโอนเกินค่าเผื่อ")); กลับมาจริง; --
spender เผื่อให้กับผู้โทรspender ไม่สามารถเป็นที่อยู่เป็นศูนย์ได้ */ ฟังก์ชั่นการเพิ่มขึ้น (ที่อยู่ Spender, UINT256 addValue) ผลตอบแทนเสมือนจริงสาธารณะ (bool) {_approve (_MSGSENDER (), Spender, _allowances [_MSGSENDER ()] [Spender] .ADD (เพิ่มค่า)); กลับมาจริง; --
spender ให้กับผู้โทรspender ไม่สามารถเป็นที่อยู่เป็นศูนย์ได้spender ต้องมีค่าเผื่อสำหรับผู้โทรอย่างน้อยsubtractedValue */ ฟังก์ชั่นการลดลง (ที่อยู่ Spender, UINT256 SUNTRACTEDVALUE) ผลตอบแทนเสมือนจริงสาธารณะ (บูล) {_Approve (_MSGSENDER (), Spender, _Allance [_MSGSENDER ()] [Spender] .sub กลับมาจริง; --
@DEV ย้าย amount โทเค็นจาก sender ไปยัง recipient
นี่คือฟังก์ชั่นภายในเทียบเท่ากับ {transfer} และสามารถใช้เพื่อ
เช่นการใช้ค่าธรรมเนียมโทเค็นอัตโนมัติกลไกการเฉือน ฯลฯ
ปล่อยเหตุการณ์ {transfer}
ความต้องการ:
sender ไม่สามารถเป็นที่อยู่เป็นศูนย์ได้recipient ไม่สามารถเป็นที่อยู่เป็นศูนย์ได้sender จะต้องมียอดคงเหลืออย่างน้อย amount */ ฟังก์ชั่น _transfer (ผู้ส่งที่อยู่ผู้รับที่อยู่ UINT256 จำนวน) เสมือนภายใน {ต้องการ (ผู้ส่ง! = ที่อยู่ (0), "ERC20: ถ่ายโอนจากที่อยู่ศูนย์"); ต้องการ (ผู้รับ! = ที่อยู่ (0), "ERC20: โอนไปยังที่อยู่ศูนย์");_beforetokentransfer (ผู้ส่งผู้รับจำนวน);
_balances [ผู้ส่ง] = _balances [ผู้ส่ง] .sub (จำนวน, "ERC20: จำนวนการโอนเกินยอดคงเหลือ"); _balances [ผู้รับ] = _balances [ผู้รับ] .Add (จำนวน); การถ่ายโอนปล่อย (ผู้ส่ง, ผู้รับ, จำนวน); -
/** @DEV สร้าง amount โทเค็นและกำหนดให้ account เพิ่มขึ้น
อุปทานทั้งหมด
ปล่อยเหตุการณ์ {transfer} ด้วย from ที่ตั้งไว้เป็นที่อยู่ศูนย์
ความต้องการ
to สามารถเป็นที่อยู่เป็นศูนย์ได้ */ ฟังก์ชั่น _mint (บัญชีที่อยู่, Uint256 จำนวน) เสมือนจริงภายใน {ต้องการ (บัญชี! = ที่อยู่ (0), "ERC20: MINT ไปยังที่อยู่ศูนย์");_beforetokentransfer (ที่อยู่ (0), บัญชี, จำนวนเงิน);
_totalsUpply = _totalsUpply.add (จำนวน); _balances [บัญชี] = _balances [บัญชี] .Add (จำนวน); การถ่ายโอนปล่อยออกมา (ที่อยู่ (0), บัญชี, จำนวนเงิน); -
-
@DEV ทำลายโทเค็น amount จาก account ลดไฟล์
อุปทานทั้งหมด
ปล่อยเหตุการณ์ {transfer} ด้วย to ตั้งค่าเป็นศูนย์ที่อยู่
ความต้องการ
account ไม่สามารถเป็นที่อยู่เป็นศูนย์ได้account ต้องมีโทเค็น amount อย่างน้อย */ ฟังก์ชั่น _burn (บัญชีที่อยู่, Uint256 จำนวน) เสมือนจริงภายใน {ต้องการ (บัญชี! = ที่อยู่ (0), "ERC20: เผาจากที่อยู่ศูนย์");_beforetokentransfer (บัญชีที่อยู่ (0), จำนวนเงิน);
_balances [บัญชี] = _balances [บัญชี] .sub (จำนวน, "ERC20: จำนวนเงินที่เผาไหม้เกินยอดคงเหลือ"); _totalsUpply = _totalsUpply.sub (จำนวน); การถ่ายโอนปล่อยออกมา (บัญชีที่อยู่ (0), จำนวนเงิน); -
-
@DEV ตั้งค่า amount เป็นค่าเผื่อของ spender เหนือโทเค็นของ owner
ฟังก์ชั่นภายในนี้เทียบเท่ากับ approve และสามารถนำมาใช้
เช่นชุดค่าเผื่ออัตโนมัติสำหรับระบบย่อยบางอย่าง ฯลฯ
ปล่อยเหตุการณ์ {การอนุมัติ}
ความต้องการ:
owner ไม่สามารถเป็นที่อยู่เป็นศูนย์ได้spender ไม่สามารถเป็นที่อยู่เป็นศูนย์ได้ */ ฟังก์ชั่น _approve (เจ้าของที่อยู่, ที่อยู่ Spender, Uint256 จำนวน) เสมือนจริงภายใน {ต้องการ (เจ้าของ! = ที่อยู่ (0), "ERC20: อนุมัติจากที่อยู่ศูนย์"); ต้องการ (Spender! = ที่อยู่ (0), "ERC20: อนุมัติที่อยู่ศูนย์");_allowances [เจ้าของ] [Spender] = จำนวน; การอนุมัติปล่อยออกมา (เจ้าของ, แมงมุม, จำนวน); -
-
-
from และ to จนถึงทั้งไม่เป็นศูนย์ amount โทเค็น fromtofrom ศูนย์เป็นศูนย์ amount โทเค็นจะถูกทำ toto เป็นศูนย์ amount โทเค็น from S จากจะถูกเผาfrom และ to ยังไม่เคยเป็นศูนย์// ใบอนุญาตบางส่วน: MIT
Pragma Solidity ^0.6.0;
-
@DEV สัญญานี้ขยายโทเค็น ERC20 ด้วยกลไกสแน็ปช็อต เมื่อสร้างสแน็ปช็อตยอดคงเหลือและ
การจัดหาทั้งหมดในเวลานั้นจะถูกบันทึกไว้สำหรับการเข้าถึงในภายหลัง
สิ่งนี้สามารถใช้ในการสร้างกลไกอย่างปลอดภัยตามยอดคงเหลือโทเค็นเช่นการจ่ายเงินปันผลที่ไม่น่าเชื่อถือหรือการลงคะแนนถ่วงน้ำหนัก
ในการใช้งานที่ไร้เดียงสาเป็นไปได้ที่จะทำการโจมตีแบบ "ใช้จ่ายสองครั้ง" โดยนำยอดคงเหลือเดียวกันจากที่แตกต่างกัน
บัญชี ด้วยการใช้สแน็ปช็อตเพื่อคำนวณเงินปันผลหรืออำนาจการลงคะแนนการโจมตีเหล่านั้นจะไม่นำไปใช้อีกต่อไป นอกจากนี้ยังสามารถ
ใช้ในการสร้างกลไกการฟอร์ก ERC20 ที่มีประสิทธิภาพ
สแน็ปช็อตถูกสร้างขึ้นโดยฟังก์ชัน {_snapshot} ภายในซึ่งจะปล่อยเหตุการณ์ {snapshot} และส่งคืน a
รหัสสแน็ปช็อต หากต้องการรับการจัดหาทั้งหมดในเวลาของสแน็ปช็อตให้เรียกใช้ฟังก์ชัน {totalSupplyat} ด้วยสแนปชอต
id. หากต้องการรับยอดคงเหลือของบัญชีในเวลาที่สแน็ปช็อตโทรหาฟังก์ชั่น {BalanceOfat} ด้วยรหัสสแนปชอต
และที่อยู่บัญชี
==== ต้นทุนก๊าซ
สแน็ปช็อตมีประสิทธิภาพ การสร้างสแน็ปช็อตคือ o (1) การดึงยอดคงเหลือหรือการจัดหาทั้งหมดจากสแน็ปช็อตคือ _o (บันทึก
n) _ ในจำนวนสแน็ปช็อตที่สร้างขึ้นแม้ว่า n สำหรับบัญชีเฉพาะโดยทั่วไปจะมีมาก
เล็กลงเนื่องจากยอดคงเหลือเหมือนกันในสแน็ปช็อตที่ตามมาจะถูกเก็บไว้เป็นรายการเดียว
มีค่าใช้จ่ายคงที่สำหรับการถ่ายโอน ERC20 ปกติเนื่องจากการทำบัญชีสแน็ปช็อตเพิ่มเติม ค่าใช้จ่ายนี้คือ
มีความสำคัญเฉพาะสำหรับการถ่ายโอนครั้งแรกที่ติดตามภาพรวมทันทีสำหรับบัญชีเฉพาะ ภายหลัง
การถ่ายโอนจะมีค่าใช้จ่ายปกติจนกว่าจะถึงสแน็ปช็อตถัดไปและอื่น ๆ */บทคัดย่อสัญญา ERC20SNAPSHOT คือ ERC20 {// แรงบันดาลใจจาก Jordi Baylina ของ Jordi Baylina เพื่อบันทึกยอดคงเหลือทางประวัติศาสตร์: // https://github.com/giveth/minimd/blob/EA04D950EEA
ใช้ Safemath สำหรับ UINT256; ใช้อาร์เรย์สำหรับ UINT256 []; ใช้เคาน์เตอร์สำหรับเคาน์เตอร์เคาน์เตอร์;
// ค่า snapshotted มีอาร์เรย์ของ ID และค่าที่สอดคล้องกับ ID นั้น สิ่งเหล่านี้อาจเป็นอาร์เรย์ของ A // snapshot struct แต่นั่นจะเป็นอุปสรรคต่อการใช้งานฟังก์ชั่นที่ทำงานบนอาร์เรย์ สแน็ปช็อตโครงสร้าง {uint256 [] ids; uint256 [] ค่า; -
การแม็พ (ที่อยู่ => snapshots) ส่วนตัว _accountbalancesnapshots; Snapshots ส่วนตัว _totalsUpplysnapshots;
// Snapshot IDs เพิ่มขึ้น monotonically โดยค่าแรกคือ 1. id ของ 0 ไม่ถูกต้อง counters.counter ส่วนตัว _currentsnapshotid;
-
id */ Event Snapshot (UINT256 ID);-
@DEV สร้างสแนปชอตใหม่และส่งคืนรหัสสแนปชอต
ปล่อยเหตุการณ์ {snapshot} ที่มี ID เดียวกัน
{_snapshot} อยู่ internal และคุณต้องตัดสินใจว่าจะเปิดเผยอย่างไรจากภายนอก การใช้งานของมันอาจถูก จำกัด อยู่ที่ก
ชุดบัญชีตัวอย่างเช่นการใช้ {AccessControl} หรืออาจเปิดให้สาธารณชนเข้าชม
[คำเตือน]
-
ในขณะที่จำเป็นต้องเปิดใช้วิธีการโทร {_snapshot} สำหรับกลไกการลดความน่าเชื่อถือบางอย่างเช่นการฟอร์ก
คุณต้องพิจารณาว่าผู้โจมตีสามารถใช้งานได้สองวิธี
ก่อนอื่นสามารถใช้เพื่อเพิ่มค่าใช้จ่ายในการดึงค่าจากสแน็ปช็อตแม้ว่ามันจะเติบโต
ลอการิทึมจึงทำให้การโจมตีครั้งนี้ไม่ได้ผลในระยะยาว ประการที่สองมันสามารถใช้ในการกำหนดเป้าหมาย
บัญชีเฉพาะและเพิ่มค่าใช้จ่ายของการโอน ERC20 สำหรับพวกเขาในวิธีที่ระบุในต้นทุนก๊าซ
ส่วนด้านบน
เราไม่ได้วัดตัวเลขจริง หากนี่คือสิ่งที่คุณสนใจโปรดติดต่อเรา
==== */ ฟังก์ชั่น _snapshot () การส่งคืนเสมือนภายใน (uint256) {_currentsnapshotid.increment ();
uint256 currentId = _currentsnapshotid.current (); ปล่อยสแน็ปช็อต (currentId); ส่งคืน currentId; -
-
@DEV ดึงยอดคงเหลือของ account ณ เวลาที่ snapshotId ถูกสร้างขึ้น */ ฟังก์ชั่น Balanceofat (บัญชีที่อยู่, UINT256 Snapshotid) การส่งคืนมุมมองสาธารณะ (UINT256) {(bool snapshotted, uint256 ค่า) = _valueat (snapshotid, _accountbalancesnapshots [บัญชี]);
ส่งคืน snapshotted? มูลค่า: ยอดคงเหลือ (บัญชี); -
-
@DEV ดึงการจัดหาทั้งหมดในเวลาที่ snapshotId ถูกสร้างขึ้น */ ฟังก์ชั่น totalsUpplyat (UINT256 snapshotid) การส่งคืนมุมมองสาธารณะ (UINT256) {(bool snapshotted, uint256 ค่า) = _valueat (snapshotid, _totalsupplysnapshots);
ส่งคืน snapshotted? ค่า: totalsUpply (); -
// อัปเดตยอดคงเหลือและ/หรือสแน็ปช็อตซัพพลายทั้งหมดก่อนที่ค่าจะถูกแก้ไข สิ่งนี้ถูกนำไปใช้ // ใน hook _beforetokentransfer ซึ่งดำเนินการสำหรับการดำเนินการ _mint, _burn และ _transfer ฟังก์ชั่น _beforetokentRansfer (ที่อยู่จากที่อยู่ถึง, UINT256 จำนวน) การแทนที่เสมือนภายใน {super._beforetokentransfer (จาก, ถึง, จำนวน);
if (จาก == ที่อยู่ (0)) {// mint _updateAccountSnapShot (ถึง); _upDatetotalsUpplysnapshot (); } อื่นถ้า (ถึง == ที่อยู่ (0)) {// เบิร์น _upDateAccountSnapShot (จาก); _upDatetotalsUpplysnapshot (); } else {// transfer _updateaccountsnapshot (จาก); _UpDateAccountSnapShot (ถึง); -
ฟังก์ชั่น _valueat (UINT256 Snapshotid, สแน็ปช็อตสแน็ปช็อตสแน็ปช็อตสแนปชอต) การส่งคืนมุมมองส่วนตัว (บูล, uint256) {ต้องการ (snapshotid> 0, "erc20snapshot: id คือ 0"); // SOLHINT-DISABLE-NEXT-LINE-LINE-LINE ความยาวต้องการ (snapshotid <= _currentsNapShotid.current (), "ERC20SNAPSHOT: ไม่มี ID");
// When a valid snapshot is queried, there are three possibilities:
// a) The queried value was not modified after the snapshot was taken. Therefore, a snapshot entry was never
// created for this id, and all stored snapshot ids are smaller than the requested one. The value that corresponds
// to this id is the current one.
// b) The queried value was modified after the snapshot was taken. Therefore, there will be an entry with the
// requested id, and its value is the one to return.
// c) More snapshots were created after the requested one, and the queried value was later modified. There will be
// no entry for the requested id: the value that corresponds to it is that of the smallest snapshot id that is
// larger than the requested one.
//
// In summary, we need to find an element in an array, returning the index of the smallest value that is larger if
// it is not found, unless said value doesn't exist (e.g. when all values are smaller). Arrays.findUpperBound does
// exactly this.
uint256 index = snapshots.ids.findUpperBound(snapshotId);
if (index == snapshots.ids.length) {
return (false, 0);
} else {
return (true, snapshots.values[index]);
}
-
ฟังก์ชั่น _upDateAccountSnapShot (บัญชีที่อยู่) ส่วนตัว {_updatesNapShot (_AccountBalancesNapShots [บัญชี], สมดุล (บัญชี)); -
ฟังก์ชั่น _UpDatetOtAlsUppLysNapShot () ส่วนตัว {_updatesNapShot (_TotalsUpplysNapShots, totalsUpply ()); -
ฟังก์ชั่น _updatesNapShot (สแน็ปช็อตที่เก็บข้อมูลสแน็ปช็อต, UINT256 CurrentValue) ส่วนตัว {UINT256 currentId = _currentsNapShotid.current (); if (_lastsnapshotid (snapshots.ids) <currentId) {snapshots.ids.push (currentId); snapshots.values.push (currentValue); -
ฟังก์ชั่น _lastsnapshotid (uint256 [] รหัสที่เก็บข้อมูล) การส่งคืนมุมมองส่วนตัว (uint256) {ถ้า (ids.length == 0) {return 0; } else {return ids [ids.length - 1]; -
// ใบอนุญาตบางส่วน: MIT
Pragma Solidity ^0.6.0;
-
@DEV ห้องสมุดสำหรับการจัดการ
https://en.wikipedia.org/wiki/set_(abstract_data_type)
ประเภท.
ชุดมีคุณสมบัติดังต่อไปนี้:
(o (1))
ตัวอย่างสัญญา {
// Add the library methods
using EnumerableSet for EnumerableSet.AddressSet;
// Declare a set state variable
EnumerableSet.AddressSet private mySet;
-
ณ v3.0.0 เฉพาะชุด address ประเภท ( AddressSet ) และ uint256
( UintSet ) ได้รับการสนับสนุน */ Library EnumerableSet {// ในการใช้ไลบรารีนี้สำหรับหลายประเภทด้วยรหัสเล็ก ๆ น้อย ๆ // การทำซ้ำเท่าที่เป็นไปได้เราเขียนในแง่ของประเภทชุดทั่วไปด้วย // bytes32 ค่า // การใช้งานชุดใช้ฟังก์ชั่นส่วนตัวและการใช้งานผู้ใช้ // การใช้งาน (เช่นชุดที่อยู่) เป็นเพียงการห่อหุ้มรอบ ๆ ชุด // พื้นฐาน // ซึ่งหมายความว่าเราสามารถสร้างชุดใหม่สำหรับประเภทที่พอดี // ใน Bytes32
ชุดโครงสร้าง {// การจัดเก็บของค่าตั้งค่า bytes32 [] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping (bytes32 => uint256) _indexes;
-
-
-
@DEV ลบค่าออกจากชุด o (1)
ส่งคืนจริงหากค่าถูกลบออกจากชุดนั่นคือถ้าเป็น
ปัจจุบัน. */ ฟังก์ชั่น _remove (ตั้งค่าชุดเก็บข้อมูล, bytes32 value) การส่งคืนส่วนตัว (บูล) {// เราอ่านและจัดเก็บดัชนีของค่าเพื่อป้องกันการอ่านหลายครั้งจากช่องเก็บข้อมูลเดียวกัน UINT256 ValueIndex = set._indexes [ค่า];
if (valueIndex! = 0) {// เทียบเท่ากับมี (set, value) // เพื่อลบองค์ประกอบจากอาร์เรย์ _values ใน o (1) เราเปลี่ยนองค์ประกอบเพื่อลบด้วยอันสุดท้ายใน // อาร์เรย์แล้วลบองค์ประกอบสุดท้าย (บางครั้งเรียกว่า 'swap และ pop') // สิ่งนี้ปรับเปลี่ยนลำดับของอาร์เรย์ตามที่ระบุไว้ใน {at}
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
// When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
// so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
bytes32 lastvalue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastvalue;
// Update the index for the moved value
set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {return false; -
-
-
-
index ตำแหน่งในชุด o (1)index จะต้องน้อยกว่า {ความยาว} อย่างเคร่งครัด */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; -// AddressSet
struct AddressSet { Set _inner; -
-
-
-
-
-
index in the set. O(1).index must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint256(_at(set._inner, index))); -// UintSet
struct UintSet { Set _inner; -
-
-
-
-
-
index in the set. O(1).index must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); -// Partial License: MIT
pragma solidity ^0.6.0;
-
@dev Contract module that allows children to implement role-based access
control mechanisms.
Roles are referred to by their bytes32 identifier. These should be exposed
in the external API and be unique. The best way to achieve this is by
using public constant hash digests:
bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
Roles can be used to represent a set of permissions. To restrict access to a
function call, use {hasRole}:
function foo() public {
require(hasRole(MY_ROLE, msg.sender));
...
-
Roles can be granted and revoked dynamically via the {grantRole} and
{revokeRole} functions. Each role has an associated admin role, and only
accounts that have a role's admin role can call {grantRole} and {revokeRole}.
By default, the admin role for all roles is DEFAULT_ADMIN_ROLE , which means
that only accounts with this role will be able to grant or revoke other
roles. More complex role relationships can be created by using
{_setRoleAdmin}.
WARNING: The DEFAULT_ADMIN_ROLE is also its own admin: it has permission to
grant and revoke this role. Extra precautions should be taken to secure
accounts that have been granted it. */ abstract contract AccessControl is Context { using EnumerableSet for EnumerableSet.AddressSet; using Address for address;
struct RoleData { EnumerableSet.AddressSet members; bytes32 adminRole; -
mapping (bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
-
newAdminRole is set as role 's admin role, replacing previousAdminRoleDEFAULT_ADMIN_ROLE is the starting admin for all roles, despite-
account is granted role .sender is the account that originated the contract call, an admin role-
account is revoked role .sender is the account that originated the contract call:revokeRole , it is the admin role bearerrenounceRole , it is the role bearer (ie account ) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);-
true if account has been granted role . */ function hasRole(bytes32 role, address account) public view returns (bool) { return _roles[role].members.contains(account); --
role . สามารถใช้งานได้-
role . index must be a-
role . See {grantRole} and-
@dev Grants role to account .
If account had not been already granted role , emits a {RoleGranted}
เหตุการณ์.
ความต้องการ:
role 's admin role. */ function grantRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");_grantRole(role, account); -
-
@dev Revokes role from account .
If account had been granted role , emits a {RoleRevoked} event.
ความต้องการ:
role 's admin role. */ function revokeRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");_revokeRole(role, account); -
-
@dev Revokes role from the calling account.
Roles are often managed via {grantRole} and {revokeRole}: this function's
purpose is to provide a mechanism for accounts to lose their privileges
if they are compromised (such as when a trusted device is misplaced).
If the calling account had been granted role , emits a {RoleRevoked}
เหตุการณ์.
ความต้องการ:
account . */ function renounceRole(bytes32 role, address account) public virtual { require(account == _msgSender(), "AccessControl: can only renounce roles for self");_revokeRole(role, account); -
-
role to account .account had not been already granted role , emits a {RoleGranted}-
adminRole as role 's admin role.function _grantRole(bytes32 role, address account) private { if (_roles[role].members.add(account)) { emit RoleGranted(role, account, _msgSender()); -
function _revokeRole(bytes32 role, address account) private { if (_roles[role].members.remove(account)) { emit RoleRevoked(role, account, _msgSender()); -
pragma solidity 0.6.8;
contract QXToken is Context, AccessControl, ERC20Snapshot { bytes32 public constant SNAPSHOT_ROLE = keccak256("SNAPSHOT_ROLE");
constructor(uint256 amount, uint8 decimals) ERC20("QX ERC20", "QX") public {
_setupDecimals(decimals);
_mint(msg.sender, amount);
// set up required roles
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
_setupRole(SNAPSHOT_ROLE, _msgSender());
}
/**
* @dev Creates a new snapshot and returns its snapshot id.
* Emits a {Snapshot} event that contains the same id.
*/
function snapshot() public {
require(hasRole(SNAPSHOT_ROLE, _msgSender()), "Must have snapshot role to create a snapshot");
_snapshot();
}
-