mirror of
https://github.com/grassrootseconomics/erc20-pool.git
synced 2026-05-14 11:58:45 +02:00
Add quoter example contract for decimals translation
This commit is contained in:
1
python/erc20_pool/data/DecimalQuote.bin
Normal file
1
python/erc20_pool/data/DecimalQuote.bin
Normal file
@@ -0,0 +1 @@
|
||||
608060405234801561001057600080fd5b506108ed806100206000396000f3fe608060405234801561001057600080fd5b5060043610610048576000357c010000000000000000000000000000000000000000000000000000000090048063dbb21d401461004d575b600080fd5b6100676004803603810190610062919061044b565b61007d565b60405161007491906104ad565b60405180910390f35b600080600080600060608873ffffffffffffffffffffffffffffffffffffffff166040516024016040516020818303038152906040527f313ce567000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161012e9190610539565b6000604051808303816000865af19150503d806000811461016b576040519150601f19603f3d011682016040523d82523d6000602084013e610170565b606091505b508092508193505050816101b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101b0906105ad565b60405180910390fd5b808060200190518101906101cd9190610606565b94508773ffffffffffffffffffffffffffffffffffffffff166040516024016040516020818303038152906040527f313ce567000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516102769190610539565b6000604051808303816000865af19150503d80600081146102b3576040519150601f19603f3d011682016040523d82523d6000602084013e6102b8565b606091505b50809250819350505081610301576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102f8906105ad565b60405180910390fd5b808060200190518101906103159190610606565b93508460ff168460ff16036103315786955050505050506103ab565b8460ff168460ff16111561037757848461034b9190610662565b60ff16925082600a61035d91906107ca565b9250828761036b9190610844565b955050505050506103ab565b83856103839190610662565b60ff16925082600a61039591906107ca565b925082876103a39190610875565b955050505050505b9392505050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103e2826103b7565b9050919050565b6103f2816103d7565b81146103fd57600080fd5b50565b60008135905061040f816103e9565b92915050565b6000819050919050565b61042881610415565b811461043357600080fd5b50565b6000813590506104458161041f565b92915050565b600080600060608486031215610464576104636103b2565b5b600061047286828701610400565b935050602061048386828701610400565b925050604061049486828701610436565b9150509250925092565b6104a781610415565b82525050565b60006020820190506104c2600083018461049e565b92915050565b600081519050919050565b600081905092915050565b60005b838110156104fc5780820151818401526020810190506104e1565b60008484015250505050565b6000610513826104c8565b61051d81856104d3565b935061052d8185602086016104de565b80840191505092915050565b60006105458284610508565b915081905092915050565b600082825260208201905092915050565b7f4552525f544f4b454e0000000000000000000000000000000000000000000000600082015250565b6000610597600983610550565b91506105a282610561565b602082019050919050565b600060208201905081810360008301526105c68161058a565b9050919050565b600060ff82169050919050565b6105e3816105cd565b81146105ee57600080fd5b50565b600081519050610600816105da565b92915050565b60006020828403121561061c5761061b6103b2565b5b600061062a848285016105f1565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061066d826105cd565b9150610678836105cd565b9250828203905060ff81111561069157610690610633565b5b92915050565b6000600282049050919050565b6000808291508390505b60018511156106ee578086048111156106ca576106c9610633565b5b60018516156106d95780820291505b80810290506106e785610697565b94506106ae565b94509492505050565b60008261070757600190506107c3565b8161071557600090506107c3565b816001811461072b576002811461073557610764565b60019150506107c3565b60ff84111561074757610746610633565b5b8360020a91508482111561075e5761075d610633565b5b506107c3565b5060208310610133831016604e8410600b84101617156107995782820a90508381111561079457610793610633565b5b6107c3565b6107a684848460016106a4565b925090508184048111156107bd576107bc610633565b5b81810290505b9392505050565b60006107d582610415565b91506107e083610415565b925061080d7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84846106f7565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061084f82610415565b915061085a83610415565b92508261086a57610869610815565b5b828204905092915050565b600061088082610415565b915061088b83610415565b925082820261089981610415565b915082820484148315176108b0576108af610633565b5b509291505056fea26469706673582212201acbf661561a2312e8b64602d749a5af7f05876881796fccdca1072b6ee3bf6664736f6c63430008130033
|
||||
1
python/erc20_pool/data/DecimalQuote.json
Normal file
1
python/erc20_pool/data/DecimalQuote.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"inputs":[{"internalType":"address","name":"_outToken","type":"address"},{"internalType":"address","name":"_inToken","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"valueFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
|
||||
1
python/erc20_pool/data/DecimalQuote.metadata.json
Normal file
1
python/erc20_pool/data/DecimalQuote.metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"compiler":{"version":"0.8.19+commit.7dd6d404"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"_outToken","type":"address"},{"internalType":"address","name":"_inToken","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"valueFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"compilationTarget":{"DecimalQuote.sol":"DecimalQuote"},"evmVersion":"byzantium","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"DecimalQuote.sol":{"keccak256":"0x9e5bc44ea381d6794c6bc992b8cee0b68fb700ab0ad888e5cec390d2261fd5f2","license":"AGPL-3.0-or-later","urls":["bzz-raw://a1d11d7ee1286203963eef4846272465fc7abdeb5c4e054f84fe9dada91b10ee","dweb:/ipfs/QmZQDttgfUBAJxxRpxW8JkwkWi61hNQ79NNrWD64Ak92vw"]}},"version":1}
|
||||
98
python/erc20_pool/quote.py
Normal file
98
python/erc20_pool/quote.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# standard imports
|
||||
import logging
|
||||
import os
|
||||
import enum
|
||||
|
||||
# external imports
|
||||
from chainlib.eth.constant import ZERO_ADDRESS
|
||||
from chainlib.eth.constant import ZERO_CONTENT
|
||||
from chainlib.eth.contract import (
|
||||
ABIContractEncoder,
|
||||
ABIContractDecoder,
|
||||
ABIContractType,
|
||||
abi_decode_single,
|
||||
)
|
||||
from chainlib.eth.jsonrpc import to_blockheight_param
|
||||
from chainlib.eth.error import RequestMismatchException
|
||||
from chainlib.eth.tx import (
|
||||
TxFactory,
|
||||
TxFormat,
|
||||
)
|
||||
from chainlib.jsonrpc import JSONRPCRequest
|
||||
from chainlib.block import BlockSpec
|
||||
from hexathon import (
|
||||
add_0x,
|
||||
strip_0x,
|
||||
)
|
||||
from chainlib.eth.cli.encode import CLIEncoder
|
||||
|
||||
# local imports
|
||||
from erc20_pool.data import data_dir
|
||||
|
||||
logg = logging.getLogger()
|
||||
|
||||
|
||||
class DecimalQuote(TxFactory):
|
||||
|
||||
__abi = None
|
||||
__bytecode = None
|
||||
|
||||
def constructor(self, sender_address, tx_format=TxFormat.JSONRPC, version=None):
|
||||
code = self.cargs(version=version)
|
||||
tx = self.template(sender_address, None, use_nonce=True)
|
||||
tx = self.set_code(tx, code)
|
||||
return self.finalize(tx, tx_format)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def cargs(version=None):
|
||||
code = DecimalQuote.bytecode(version=version)
|
||||
enc = ABIContractEncoder()
|
||||
args = enc.get()
|
||||
code += args
|
||||
logg.debug('constructor code: ' + args)
|
||||
return code
|
||||
|
||||
|
||||
@staticmethod
|
||||
def gas(code=None):
|
||||
return 4000000
|
||||
|
||||
|
||||
@staticmethod
|
||||
def abi():
|
||||
if DecimalQuote.__abi == None:
|
||||
f = open(os.path.join(data_dir, 'DecimalQuote.json'), 'r')
|
||||
DecimalQuote.__abi = json.load(f)
|
||||
f.close()
|
||||
return DecimalQuote.__abi
|
||||
|
||||
|
||||
@staticmethod
|
||||
def bytecode(version=None):
|
||||
if DecimalQuote.__bytecode == None:
|
||||
f = open(os.path.join(data_dir, 'DecimalQuote.bin'))
|
||||
DecimalQuote.__bytecode = f.read()
|
||||
f.close()
|
||||
return DecimalQuote.__bytecode
|
||||
|
||||
|
||||
def value_for(self, contract_address, token_address_out, token_address_in, value_in, sender_address=ZERO_ADDRESS, id_generator=None):
|
||||
j = JSONRPCRequest(id_generator)
|
||||
o = j.template()
|
||||
o['method'] = 'eth_call'
|
||||
enc = ABIContractEncoder()
|
||||
enc.method('valueFor')
|
||||
enc.typ(ABIContractType.ADDRESS)
|
||||
enc.typ(ABIContractType.ADDRESS)
|
||||
enc.typ(ABIContractType.UINT256)
|
||||
enc.address(token_address_out)
|
||||
enc.address(token_address_in)
|
||||
enc.uint256(value_in)
|
||||
data = add_0x(enc.get())
|
||||
tx = self.template(sender_address, contract_address)
|
||||
tx = self.set_code(tx, data)
|
||||
o['params'].append(self.normalize(tx))
|
||||
o['params'].append('latest')
|
||||
o = j.finalize(o)
|
||||
return o
|
||||
37
python/erc20_pool/unittest/quote.py
Normal file
37
python/erc20_pool/unittest/quote.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# standard imports
|
||||
import logging
|
||||
import time
|
||||
# external imports
|
||||
from chainlib.eth.unittest.ethtester import EthTesterCase
|
||||
from chainlib.connection import RPCConnection
|
||||
from chainlib.eth.nonce import RPCNonceOracle
|
||||
from chainlib.eth.tx import receipt
|
||||
from chainlib.eth.address import to_checksum_address
|
||||
from giftable_erc20_token.unittest import TestGiftableToken
|
||||
from eth_erc20 import ERC20
|
||||
from chainlib.eth.block import block_latest
|
||||
from eth_accounts_index.unittest import TestAccountsIndex
|
||||
from eth_accounts_index.registry import AccountRegistry
|
||||
from giftable_erc20_token import GiftableToken
|
||||
from erc20_limiter.unittest import TestLimiter
|
||||
|
||||
# local imports
|
||||
from erc20_pool.quote import DecimalQuote
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
class TestDecimalQuote(EthTesterCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDecimalQuote, self).setUp()
|
||||
self.conn = RPCConnection.connect(self.chain_spec, 'default')
|
||||
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
|
||||
c = DecimalQuote(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
(tx_hash, o) = c.constructor(self.accounts[0])
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
self.quoter_address = to_checksum_address(r['contract_address'])
|
||||
logg.debug('published quoter {}'.format(self.quoter_address))
|
||||
61
python/tests/test_quoter.py
Normal file
61
python/tests/test_quoter.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# standard imports
|
||||
import unittest
|
||||
import logging
|
||||
import os
|
||||
from chainlib.eth.nonce import RPCNonceOracle
|
||||
from chainlib.eth.tx import receipt
|
||||
from chainlib.eth.block import block_latest
|
||||
from hexathon import same as same_hex
|
||||
from eth_erc20 import ERC20
|
||||
from giftable_erc20_token import GiftableToken
|
||||
from erc20_limiter import Limiter
|
||||
|
||||
# local imports
|
||||
from erc20_pool.quote import DecimalQuote
|
||||
from erc20_pool.unittest.quote import TestDecimalQuote
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logg = logging.getLogger()
|
||||
|
||||
class TestQuote(TestDecimalQuote):
|
||||
|
||||
def setUp(self):
|
||||
super(TestQuote, self).setUp()
|
||||
self.tokens = {}
|
||||
self.publish_token('Foo token', 'FOO', 14)
|
||||
self.publish_token('Bar token', 'BAR', 18)
|
||||
self.publish_token('Baz token', 'BAZ', 11)
|
||||
|
||||
def publish_token(self, name, symbol, decimals):
|
||||
nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
|
||||
c = GiftableToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||
self.symbol = name
|
||||
self.name = symbol
|
||||
self.decimals = decimals
|
||||
(tx_hash, o) = c.constructor(self.accounts[0], self.name, self.symbol, self.decimals, expire=0)
|
||||
self.rpc.do(o)
|
||||
o = receipt(tx_hash)
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(r['status'], 1)
|
||||
address = r['contract_address']
|
||||
logg.debug('published "{}" ("{}") on address {} with hash {}'.format(name, symbol, address, tx_hash))
|
||||
self.tokens[symbol] = address
|
||||
|
||||
|
||||
def test_quote(self):
|
||||
c = DecimalQuote(self.chain_spec)
|
||||
o = c.value_for(self.quoter_address, self.tokens['FOO'], self.tokens['FOO'], 10**18, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(int(r, 16), 10**18)
|
||||
|
||||
o = c.value_for(self.quoter_address, self.tokens['FOO'], self.tokens['BAR'], 10**18, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(int(r, 16), 10**14)
|
||||
|
||||
o = c.value_for(self.quoter_address, self.tokens['FOO'], self.tokens['BAZ'], 10**18, sender_address=self.accounts[0])
|
||||
r = self.rpc.do(o)
|
||||
self.assertEqual(int(r, 16), 10**21)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user