mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
Merge pull request #1 from limetester/lime_task_branch
Lime task branch
This commit is contained in:
commit
f34b4ccb28
19 changed files with 7217 additions and 43 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -14,6 +14,7 @@
|
||||||
*/**/*tx_database*
|
*/**/*tx_database*
|
||||||
*/**/*dapps*
|
*/**/*dapps*
|
||||||
build/_vendor/pkg
|
build/_vendor/pkg
|
||||||
|
.docker-compose.yml.swp
|
||||||
|
|
||||||
#*
|
#*
|
||||||
.#*
|
.#*
|
||||||
|
|
|
||||||
|
|
@ -171,5 +171,5 @@ i4O1UeWKs9owWttan9+PI47ozBSKOTxmMqLSQ0f56Np9FJsV0ilGxRKfjhzJ4KniOMUBA7mP
|
||||||
epy6lH7HmxjjOR7eo0DaSxQGQpThAtFGwkWkFh8yki8j3E42kkrxvEyyYZDXn2YcI3bpqhJx
|
epy6lH7HmxjjOR7eo0DaSxQGQpThAtFGwkWkFh8yki8j3E42kkrxvEyyYZDXn2YcI3bpqhJx
|
||||||
PtwCMZUJ3kc/skOrs6bOI19iBNaEoNX5Dllm7UHjOgWNDQkcCuOCxucKano=
|
PtwCMZUJ3kc/skOrs6bOI19iBNaEoNX5Dllm7UHjOgWNDQkcCuOCxucKano=
|
||||||
=arte
|
=arte
|
||||||
-----END PGP PUBLIC KEY BLOCK------
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ func TestWatchNewFile(t *testing.T) {
|
||||||
func TestWatchNoDir(t *testing.T) {
|
func TestWatchNoDir(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
// Create ks but not the directory that it watches.
|
// Create ks but not the directory that it watches.
|
||||||
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int()))
|
dir := filepath.Join(t.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int()))
|
||||||
ks := NewKeyStore(dir, LightScryptN, LightScryptP)
|
ks := NewKeyStore(dir, LightScryptN, LightScryptP)
|
||||||
list := ks.Accounts()
|
list := ks.Accounts()
|
||||||
if len(list) > 0 {
|
if len(list) > 0 {
|
||||||
|
|
@ -126,7 +126,6 @@ func TestWatchNoDir(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Create the directory and copy a key file into it.
|
// Create the directory and copy a key file into it.
|
||||||
os.MkdirAll(dir, 0700)
|
os.MkdirAll(dir, 0700)
|
||||||
defer os.RemoveAll(dir)
|
|
||||||
file := filepath.Join(dir, "aaa")
|
file := filepath.Join(dir, "aaa")
|
||||||
if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil {
|
if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,8 @@ import (
|
||||||
// TestImportRaw tests clef --importraw
|
// TestImportRaw tests clef --importraw
|
||||||
func TestImportRaw(t *testing.T) {
|
func TestImportRaw(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||||
t.Cleanup(func() { os.Remove(keyPath) })
|
|
||||||
|
|
||||||
t.Run("happy-path", func(t *testing.T) {
|
t.Run("happy-path", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
@ -68,9 +67,8 @@ func TestImportRaw(t *testing.T) {
|
||||||
// TestListAccounts tests clef --list-accounts
|
// TestListAccounts tests clef --list-accounts
|
||||||
func TestListAccounts(t *testing.T) {
|
func TestListAccounts(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||||
t.Cleanup(func() { os.Remove(keyPath) })
|
|
||||||
|
|
||||||
t.Run("no-accounts", func(t *testing.T) {
|
t.Run("no-accounts", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
@ -97,9 +95,8 @@ func TestListAccounts(t *testing.T) {
|
||||||
// TestListWallets tests clef --list-wallets
|
// TestListWallets tests clef --list-wallets
|
||||||
func TestListWallets(t *testing.T) {
|
func TestListWallets(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||||
t.Cleanup(func() { os.Remove(keyPath) })
|
|
||||||
|
|
||||||
t.Run("no-accounts", func(t *testing.T) {
|
t.Run("no-accounts", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeJWTSecret() (string, [32]byte, error) {
|
func makeJWTSecret(t *testing.T) (string, [32]byte, error) {
|
||||||
var secret [32]byte
|
var secret [32]byte
|
||||||
if _, err := crand.Read(secret[:]); err != nil {
|
if _, err := crand.Read(secret[:]); err != nil {
|
||||||
return "", secret, fmt.Errorf("failed to create jwt secret: %v", err)
|
return "", secret, fmt.Errorf("failed to create jwt secret: %v", err)
|
||||||
}
|
}
|
||||||
jwtPath := filepath.Join(os.TempDir(), "jwt_secret")
|
jwtPath := filepath.Join(t.TempDir(), "jwt_secret")
|
||||||
if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(secret[:])), 0600); err != nil {
|
if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(secret[:])), 0600); err != nil {
|
||||||
return "", secret, fmt.Errorf("failed to prepare jwt secret file: %v", err)
|
return "", secret, fmt.Errorf("failed to prepare jwt secret file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -47,7 +47,7 @@ func makeJWTSecret() (string, [32]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEthSuite(t *testing.T) {
|
func TestEthSuite(t *testing.T) {
|
||||||
jwtPath, secret, err := makeJWTSecret()
|
jwtPath, secret, err := makeJWTSecret(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not make jwt secret: %v", err)
|
t.Fatalf("could not make jwt secret: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +75,7 @@ func TestEthSuite(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSnapSuite(t *testing.T) {
|
func TestSnapSuite(t *testing.T) {
|
||||||
jwtPath, secret, err := makeJWTSecret()
|
jwtPath, secret, err := makeJWTSecret(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not make jwt secret: %v", err)
|
t.Fatalf("could not make jwt secret: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,7 @@ import (
|
||||||
// TestExport does a basic test of "geth export", exporting the test-genesis.
|
// TestExport does a basic test of "geth export", exporting the test-genesis.
|
||||||
func TestExport(t *testing.T) {
|
func TestExport(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
outfile := fmt.Sprintf("%v/testExport.out", os.TempDir())
|
outfile := fmt.Sprintf("%v/testExport.out", t.TempDir())
|
||||||
defer os.Remove(outfile)
|
|
||||||
geth := runGeth(t, "--datadir", initGeth(t), "export", outfile)
|
geth := runGeth(t, "--datadir", initGeth(t), "export", outfile)
|
||||||
geth.WaitExit()
|
geth.WaitExit()
|
||||||
if have, want := geth.ExitStatus(), 0; have != want {
|
if have, want := geth.ExitStatus(), 0; have != want {
|
||||||
|
|
|
||||||
|
|
@ -201,9 +201,8 @@ func TestFileOut(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
have, want []byte
|
have, want []byte
|
||||||
err error
|
err error
|
||||||
path = fmt.Sprintf("%s/test_file_out-%d", os.TempDir(), rand.Int63())
|
path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63())
|
||||||
)
|
)
|
||||||
t.Cleanup(func() { os.Remove(path) })
|
|
||||||
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "logtest"); err != nil {
|
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "logtest"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -222,9 +221,8 @@ func TestRotatingFileOut(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
have, want []byte
|
have, want []byte
|
||||||
err error
|
err error
|
||||||
path = fmt.Sprintf("%s/test_file_out-%d", os.TempDir(), rand.Int63())
|
path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63())
|
||||||
)
|
)
|
||||||
t.Cleanup(func() { os.Remove(path) })
|
|
||||||
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "--log.rotate", "logtest"); err != nil {
|
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "--log.rotate", "logtest"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,18 +29,12 @@ import (
|
||||||
|
|
||||||
// TestExport does basic sanity checks on the export/import functionality
|
// TestExport does basic sanity checks on the export/import functionality
|
||||||
func TestExport(t *testing.T) {
|
func TestExport(t *testing.T) {
|
||||||
f := fmt.Sprintf("%v/tempdump", os.TempDir())
|
f := fmt.Sprintf("%v/tempdump", t.TempDir())
|
||||||
defer func() {
|
|
||||||
os.Remove(f)
|
|
||||||
}()
|
|
||||||
testExport(t, f)
|
testExport(t, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExportGzip(t *testing.T) {
|
func TestExportGzip(t *testing.T) {
|
||||||
f := fmt.Sprintf("%v/tempdump.gz", os.TempDir())
|
f := fmt.Sprintf("%v/tempdump.gz", t.TempDir())
|
||||||
defer func() {
|
|
||||||
os.Remove(f)
|
|
||||||
}()
|
|
||||||
testExport(t, f)
|
testExport(t, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,20 +93,14 @@ func testExport(t *testing.T, f string) {
|
||||||
|
|
||||||
// TestDeletionExport tests if the deletion markers can be exported/imported correctly
|
// TestDeletionExport tests if the deletion markers can be exported/imported correctly
|
||||||
func TestDeletionExport(t *testing.T) {
|
func TestDeletionExport(t *testing.T) {
|
||||||
f := fmt.Sprintf("%v/tempdump", os.TempDir())
|
f := fmt.Sprintf("%v/tempdump", t.TempDir())
|
||||||
defer func() {
|
|
||||||
os.Remove(f)
|
|
||||||
}()
|
|
||||||
testDeletion(t, f)
|
testDeletion(t, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDeletionExportGzip tests if the deletion markers can be exported/imported
|
// TestDeletionExportGzip tests if the deletion markers can be exported/imported
|
||||||
// correctly with gz compression.
|
// correctly with gz compression.
|
||||||
func TestDeletionExportGzip(t *testing.T) {
|
func TestDeletionExportGzip(t *testing.T) {
|
||||||
f := fmt.Sprintf("%v/tempdump.gz", os.TempDir())
|
f := fmt.Sprintf("%v/tempdump.gz", t.TempDir())
|
||||||
defer func() {
|
|
||||||
os.Remove(f)
|
|
||||||
}()
|
|
||||||
testDeletion(t, f)
|
testDeletion(t, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,10 +159,7 @@ func testDeletion(t *testing.T, f string) {
|
||||||
// TestImportFutureFormat tests that we reject unsupported future versions.
|
// TestImportFutureFormat tests that we reject unsupported future versions.
|
||||||
func TestImportFutureFormat(t *testing.T) {
|
func TestImportFutureFormat(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
f := fmt.Sprintf("%v/tempdump-future", os.TempDir())
|
f := fmt.Sprintf("%v/tempdump-future", t.TempDir())
|
||||||
defer func() {
|
|
||||||
os.Remove(f)
|
|
||||||
}()
|
|
||||||
fh, err := os.OpenFile(f, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
fh, err := os.OpenFile(f, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReadWriteFreezerTableMeta(t *testing.T) {
|
func TestReadWriteFreezerTableMeta(t *testing.T) {
|
||||||
f, err := os.CreateTemp(os.TempDir(), "*")
|
f, err := os.CreateTemp(t.TempDir(), "*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create file %v", err)
|
t.Fatalf("Failed to create file %v", err)
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
err = writeMetadata(f, newMetadata(100))
|
err = writeMetadata(f, newMetadata(100))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to write metadata %v", err)
|
t.Fatalf("Failed to write metadata %v", err)
|
||||||
|
|
@ -43,10 +44,11 @@ func TestReadWriteFreezerTableMeta(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInitializeFreezerTableMeta(t *testing.T) {
|
func TestInitializeFreezerTableMeta(t *testing.T) {
|
||||||
f, err := os.CreateTemp(os.TempDir(), "*")
|
f, err := os.CreateTemp(t.TempDir(), "*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create file %v", err)
|
t.Fatalf("Failed to create file %v", err)
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
meta, err := loadMetadata(f, uint64(100))
|
meta, err := loadMetadata(f, uint64(100))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to read metadata %v", err)
|
t.Fatalf("Failed to read metadata %v", err)
|
||||||
|
|
|
||||||
|
|
@ -572,6 +572,6 @@ func deriveChainId(v *big.Int) *big.Int {
|
||||||
}
|
}
|
||||||
return new(big.Int).SetUint64((v - 35) / 2)
|
return new(big.Int).SetUint64((v - 35) / 2)
|
||||||
}
|
}
|
||||||
v.Sub(v, big.NewInt(35))
|
vCopy := new(big.Int).Sub(v, big.NewInt(35))
|
||||||
return v.Rsh(v, 1)
|
return vCopy.Rsh(vCopy, 1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -345,6 +345,41 @@ func TestTransactionCoding(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLegacyTransaction_ConsistentV_LargeChainIds(t *testing.T) {
|
||||||
|
chainId := new(big.Int).SetUint64(13317435930671861669)
|
||||||
|
|
||||||
|
txdata := &LegacyTx{
|
||||||
|
Nonce: 1,
|
||||||
|
Gas: 1,
|
||||||
|
GasPrice: big.NewInt(2),
|
||||||
|
Data: []byte("abcdef"),
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := crypto.GenerateKey()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not generate key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := SignNewTx(key, NewEIP2930Signer(chainId), txdata)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not sign transaction: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a copy of the initial V value
|
||||||
|
preV, _, _ := tx.RawSignatureValues()
|
||||||
|
preV = new(big.Int).Set(preV)
|
||||||
|
|
||||||
|
if tx.ChainId().Cmp(chainId) != 0 {
|
||||||
|
t.Fatalf("wrong chain id: %v", tx.ChainId())
|
||||||
|
}
|
||||||
|
|
||||||
|
v, _, _ := tx.RawSignatureValues()
|
||||||
|
|
||||||
|
if v.Cmp(preV) != 0 {
|
||||||
|
t.Fatalf("wrong v value: %v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func encodeDecodeJSON(tx *Transaction) (*Transaction, error) {
|
func encodeDecodeJSON(tx *Transaction) (*Transaction, error) {
|
||||||
data, err := json.Marshal(tx)
|
data, err := json.Marshal(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
12
docker-compose/docker-compose.yml
Normal file
12
docker-compose/docker-compose.yml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
geth:
|
||||||
|
image: denislav-mladenov/go-ethereum:latest
|
||||||
|
ports:
|
||||||
|
- "8545:8545"
|
||||||
|
- "30303:30303"
|
||||||
|
volumes:
|
||||||
|
- ./data:/root/.ethereum
|
||||||
|
command: --dev --http --http.addr 0.0.0.0 --http.port 8545 --http.api eth,net,web3,personal,miner
|
||||||
|
|
||||||
17
hardhat/.gitignore
vendored
Normal file
17
hardhat/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
node_modules
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Hardhat files
|
||||||
|
/cache
|
||||||
|
/artifacts
|
||||||
|
|
||||||
|
# TypeChain files
|
||||||
|
/typechain
|
||||||
|
/typechain-types
|
||||||
|
|
||||||
|
# solidity-coverage files
|
||||||
|
/coverage
|
||||||
|
/coverage.json
|
||||||
|
|
||||||
|
# Hardhat Ignition default folder for deployments against a local node
|
||||||
|
ignition/deployments/chain-31337
|
||||||
66
hardhat/contracts/Token.sol
Normal file
66
hardhat/contracts/Token.sol
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
//SPDX-License-Identifier: UNLICENSED
|
||||||
|
|
||||||
|
// Solidity files have to start with this pragma.
|
||||||
|
// It will be used by the Solidity compiler to validate its version.
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
|
||||||
|
// This is the main building block for smart contracts.
|
||||||
|
contract Token {
|
||||||
|
// Some string type variables to identify the token.
|
||||||
|
string public name = "My Hardhat Token";
|
||||||
|
string public symbol = "MHT";
|
||||||
|
|
||||||
|
// The fixed amount of tokens, stored in an unsigned integer type variable.
|
||||||
|
uint256 public totalSupply = 1000000;
|
||||||
|
|
||||||
|
// An address type variable is used to store ethereum accounts.
|
||||||
|
address public owner;
|
||||||
|
|
||||||
|
// A mapping is a key/value map. Here we store each account's balance.
|
||||||
|
mapping(address => uint256) balances;
|
||||||
|
|
||||||
|
// The Transfer event helps off-chain applications understand
|
||||||
|
// what happens within your contract.
|
||||||
|
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contract initialization.
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
// The totalSupply is assigned to the transaction sender, which is the
|
||||||
|
// account that is deploying the contract.
|
||||||
|
balances[msg.sender] = totalSupply;
|
||||||
|
owner = msg.sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function to transfer tokens.
|
||||||
|
*
|
||||||
|
* The `external` modifier makes a function *only* callable from *outside*
|
||||||
|
* the contract.
|
||||||
|
*/
|
||||||
|
function transfer(address to, uint256 amount) external {
|
||||||
|
// Check if the transaction sender has enough tokens.
|
||||||
|
// If `require`'s first argument evaluates to `false`, the
|
||||||
|
// transaction will revert.
|
||||||
|
require(balances[msg.sender] >= amount, "Not enough tokens");
|
||||||
|
|
||||||
|
// Transfer the amount.
|
||||||
|
balances[msg.sender] -= amount;
|
||||||
|
balances[to] += amount;
|
||||||
|
|
||||||
|
// Notify off-chain applications of the transfer.
|
||||||
|
emit Transfer(msg.sender, to, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read only function to retrieve the token balance of a given account.
|
||||||
|
*
|
||||||
|
* The `view` modifier indicates that it doesn't modify the contract's
|
||||||
|
* state, which allows us to call it without executing a transaction.
|
||||||
|
*/
|
||||||
|
function balanceOf(address account) external view returns (uint256) {
|
||||||
|
return balances[account];
|
||||||
|
}
|
||||||
|
}
|
||||||
6
hardhat/hardhat.config.js
Normal file
6
hardhat/hardhat.config.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
require("@nomicfoundation/hardhat-toolbox");
|
||||||
|
|
||||||
|
/** @type import('hardhat/config').HardhatUserConfig */
|
||||||
|
module.exports = {
|
||||||
|
solidity: "0.8.24",
|
||||||
|
};
|
||||||
9
hardhat/ignition/modules/Token.js
Normal file
9
hardhat/ignition/modules/Token.js
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");
|
||||||
|
|
||||||
|
const TokenModule = buildModule("TokenModule", (m) => {
|
||||||
|
const token = m.contract("Token");
|
||||||
|
|
||||||
|
return { token };
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = TokenModule;
|
||||||
6905
hardhat/package-lock.json
generated
Normal file
6905
hardhat/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
23
hardhat/package.json
Normal file
23
hardhat/package.json
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"name": "hardhat-pacage",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "denis hardhat project",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/denislav-mladenov/go-ethereum.git"
|
||||||
|
},
|
||||||
|
"author": "denis",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/denislav-mladenov/go-ethereum/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/denislav-mladenov/go-ethereum#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
|
||||||
|
"hardhat": "^2.22.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
120
hardhat/test/Token.js
Normal file
120
hardhat/test/Token.js
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
// This is an example test file. Hardhat will run every *.js file in `test/`,
|
||||||
|
// so feel free to add new ones.
|
||||||
|
|
||||||
|
// Hardhat tests are normally written with Mocha and Chai.
|
||||||
|
|
||||||
|
// We import Chai to use its asserting functions here.
|
||||||
|
const { expect } = require("chai");
|
||||||
|
|
||||||
|
// We use `loadFixture` to share common setups (or fixtures) between tests.
|
||||||
|
// Using this simplifies your tests and makes them run faster, by taking
|
||||||
|
// advantage of Hardhat Network's snapshot functionality.
|
||||||
|
const {
|
||||||
|
loadFixture,
|
||||||
|
} = require("@nomicfoundation/hardhat-toolbox/network-helpers");
|
||||||
|
|
||||||
|
// `describe` is a Mocha function that allows you to organize your tests.
|
||||||
|
// Having your tests organized makes debugging them easier. All Mocha
|
||||||
|
// functions are available in the global scope.
|
||||||
|
//
|
||||||
|
// `describe` receives the name of a section of your test suite, and a
|
||||||
|
// callback. The callback must define the tests of that section. This callback
|
||||||
|
// can't be an async function.
|
||||||
|
describe("Token contract", function () {
|
||||||
|
// We define a fixture to reuse the same setup in every test. We use
|
||||||
|
// loadFixture to run this setup once, snapshot that state, and reset Hardhat
|
||||||
|
// Network to that snapshot in every test.
|
||||||
|
async function deployTokenFixture() {
|
||||||
|
// Get the Signers here.
|
||||||
|
const [owner, addr1, addr2] = await ethers.getSigners();
|
||||||
|
|
||||||
|
// To deploy our contract, we just have to call ethers.deployContract and await
|
||||||
|
// its waitForDeployment() method, which happens once its transaction has been
|
||||||
|
// mined.
|
||||||
|
const hardhatToken = await ethers.deployContract("Token");
|
||||||
|
|
||||||
|
await hardhatToken.waitForDeployment();
|
||||||
|
|
||||||
|
// Fixtures can return anything you consider useful for your tests
|
||||||
|
return { hardhatToken, owner, addr1, addr2 };
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can nest describe calls to create subsections.
|
||||||
|
describe("Deployment", function () {
|
||||||
|
// `it` is another Mocha function. This is the one you use to define each
|
||||||
|
// of your tests. It receives the test name, and a callback function.
|
||||||
|
//
|
||||||
|
// If the callback function is async, Mocha will `await` it.
|
||||||
|
it("Should set the right owner", async function () {
|
||||||
|
// We use loadFixture to setup our environment, and then assert that
|
||||||
|
// things went well
|
||||||
|
const { hardhatToken, owner } = await loadFixture(deployTokenFixture);
|
||||||
|
|
||||||
|
// `expect` receives a value and wraps it in an assertion object. These
|
||||||
|
// objects have a lot of utility methods to assert values.
|
||||||
|
|
||||||
|
// This test expects the owner variable stored in the contract to be
|
||||||
|
// equal to our Signer's owner.
|
||||||
|
expect(await hardhatToken.owner()).to.equal(owner.address);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should assign the total supply of tokens to the owner", async function () {
|
||||||
|
const { hardhatToken, owner } = await loadFixture(deployTokenFixture);
|
||||||
|
const ownerBalance = await hardhatToken.balanceOf(owner.address);
|
||||||
|
expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Transactions", function () {
|
||||||
|
it("Should transfer tokens between accounts", async function () {
|
||||||
|
const { hardhatToken, owner, addr1, addr2 } = await loadFixture(
|
||||||
|
deployTokenFixture
|
||||||
|
);
|
||||||
|
// Transfer 50 tokens from owner to addr1
|
||||||
|
await expect(
|
||||||
|
hardhatToken.transfer(addr1.address, 50)
|
||||||
|
).to.changeTokenBalances(hardhatToken, [owner, addr1], [-50, 50]);
|
||||||
|
|
||||||
|
// Transfer 50 tokens from addr1 to addr2
|
||||||
|
// We use .connect(signer) to send a transaction from another account
|
||||||
|
await expect(
|
||||||
|
hardhatToken.connect(addr1).transfer(addr2.address, 50)
|
||||||
|
).to.changeTokenBalances(hardhatToken, [addr1, addr2], [-50, 50]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should emit Transfer events", async function () {
|
||||||
|
const { hardhatToken, owner, addr1, addr2 } = await loadFixture(
|
||||||
|
deployTokenFixture
|
||||||
|
);
|
||||||
|
|
||||||
|
// Transfer 50 tokens from owner to addr1
|
||||||
|
await expect(hardhatToken.transfer(addr1.address, 50))
|
||||||
|
.to.emit(hardhatToken, "Transfer")
|
||||||
|
.withArgs(owner.address, addr1.address, 50);
|
||||||
|
|
||||||
|
// Transfer 50 tokens from addr1 to addr2
|
||||||
|
// We use .connect(signer) to send a transaction from another account
|
||||||
|
await expect(hardhatToken.connect(addr1).transfer(addr2.address, 50))
|
||||||
|
.to.emit(hardhatToken, "Transfer")
|
||||||
|
.withArgs(addr1.address, addr2.address, 50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should fail if sender doesn't have enough tokens", async function () {
|
||||||
|
const { hardhatToken, owner, addr1 } = await loadFixture(
|
||||||
|
deployTokenFixture
|
||||||
|
);
|
||||||
|
const initialOwnerBalance = await hardhatToken.balanceOf(owner.address);
|
||||||
|
|
||||||
|
// Try to send 1 token from addr1 (0 tokens) to owner.
|
||||||
|
// `require` will evaluate false and revert the transaction.
|
||||||
|
await expect(
|
||||||
|
hardhatToken.connect(addr1).transfer(owner.address, 1)
|
||||||
|
).to.be.revertedWith("Not enough tokens");
|
||||||
|
|
||||||
|
// Owner balance shouldn't have changed.
|
||||||
|
expect(await hardhatToken.balanceOf(owner.address)).to.equal(
|
||||||
|
initialOwnerBalance
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue