-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce "IssueTokensFromGarage" action #295
Changes from all commits
77e5963
314a370
4658f29
b153cf7
2104fdf
0be54d7
c88e906
26252f4
7144483
c630bc8
0656a17
0b8844a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
from typing import List, Optional | ||
|
||
from common.lib9c.actions import ActionBase | ||
from common.lib9c.models.fungible_asset_value import FungibleAssetValue | ||
|
||
|
||
class FavIssueSpec: | ||
def __init__(self, fav: FungibleAssetValue): | ||
self._fav = fav | ||
|
||
@property | ||
def plain_value(self): | ||
return \ | ||
[ | ||
self._fav.plain_value, | ||
None # No Item spec | ||
] | ||
|
||
|
||
class ItemIssueSpec: | ||
def __init__(self, fungible_item_id: [str | bytes], amount: int): | ||
self.item_id = fungible_item_id if isinstance(fungible_item_id, bytes) else bytes.fromhex(fungible_item_id) | ||
self.amount = amount | ||
|
||
@property | ||
def plain_value(self): | ||
return \ | ||
[ | ||
None, # No FAV spec | ||
[ | ||
self.item_id, | ||
self.amount | ||
] | ||
] | ||
|
||
|
||
class IssueTokensFromGarage(ActionBase): | ||
""" | ||
Python port of `IssueTokensFromGarage` action from lib9c | ||
|
||
- type_id: `issue_tokens_from_garage` | ||
- values: List[spec] | ||
- spec: List[FavIssueSpec | ItemIssueSpec] | ||
""" | ||
TYPE_ID: str = "issue_tokens_from_garage" | ||
|
||
def __init__(self, *, values: List[FavIssueSpec | ItemIssueSpec], _id: Optional[str] = None): | ||
super().__init__(self.TYPE_ID, _id) | ||
self._values: List[FavIssueSpec | ItemIssueSpec] = values | ||
|
||
@property | ||
def _plain_value(self): | ||
return [x.plain_value for x in self._values] if self._values else None |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
class InvalidAmountException(Exception): | ||
pass |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,10 @@ | ||
from __future__ import annotations | ||
|
||
import hashlib | ||
import hmac | ||
|
||
import eth_utils | ||
|
||
|
||
class Address: | ||
def __init__(self, addr: str): | ||
|
@@ -20,5 +25,46 @@ def long_format(self): | |
def short_format(self): | ||
return self.raw.hex() | ||
|
||
def derive(self, key: str) -> Address: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 주소유도하는 메서드가 어디 따로 있었던걸로 기억하는데, 둘이 결과가 같을까요? 다르다면 고쳐야할것같고, 같다면 하나로 통일하는게 좋을것같습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 저도 어디 만들어둔 것 같아서 찾아봤는데 안보여서 만들었습니다. 혹 정리하다 보이면 이쪽으로 모으는걸 생각하고 있습니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기 에 있는데 return type 이 좀 다르네요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 새로 만든 코드로 통일할거라서 기존 코드에는 deprecate 표기 먼저 해놨습니다. |
||
return Address( | ||
self.__checksum_encode(hmac.new( | ||
key.encode("utf-8"), | ||
self.raw, | ||
digestmod=hashlib.sha1 | ||
).digest()) | ||
) | ||
|
||
def __checksum_encode(self, addr: bytes) -> str: # Takes a 20-byte binary address as input | ||
""" | ||
Convert input address to checksum encoded address without prefix "0x" | ||
See [ERC-55](https://eips.ethereum.org/EIPS/eip-55) | ||
|
||
:param addr: 20-bytes binary address | ||
:return: checksum encoded address as string | ||
""" | ||
hex_addr = addr.hex() | ||
checksum_buffer = "" | ||
|
||
# Treat the hex address as ascii/utf-8 for keccak256 hashing | ||
hashed_address = eth_utils.keccak(text=hex_addr).hex() | ||
|
||
# Iterate over each character in the hex address | ||
for nibble_index, character in enumerate(hex_addr): | ||
if character in "0123456789": | ||
# We can't upper-case the decimal digits | ||
checksum_buffer += character | ||
elif character in "abcdef": | ||
# Check if the corresponding hex digit (nibble) in the hash is 8 or higher | ||
hashed_address_nibble = int(hashed_address[nibble_index], 16) | ||
if hashed_address_nibble > 7: | ||
checksum_buffer += character.upper() | ||
else: | ||
checksum_buffer += character | ||
else: | ||
raise eth_utils.ValidationError( | ||
f"Unrecognized hex character {character!r} at position {nibble_index}" | ||
) | ||
return checksum_buffer | ||
|
||
def __eq__(self, other: Address): | ||
return self.raw == other.raw |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,10 +21,13 @@ def fetch_secrets(region: str, secret_arn: str) -> Dict: | |
return json.loads(resp["SecretString"]) | ||
|
||
|
||
def fetch_kms_key_id(stage: str, region: str) -> Optional[str]: | ||
def fetch_kms_key_id(stage: str, region: str, adhoc: bool = False) -> Optional[str]: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코드를 봐서는 서명용 키를 워커마다 다르게 가져가는 식인것같은데, 중복이 좀 되더라도 차라리 키별로 얻어오는 메서드를 아예 명시적으로 나눠버리는게 어떨까 싶네요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이걸 True 로 쓰는 데가 사실상 manual sign 하는 곳 (운영 계정에서 IssueToken + Transfer Assets) 밖에 없기는 한데 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A계정으로 B계정의 일을 처리하는게(혹은 반대) 겁나는 상황인건데, 이걸 막을수있을까요? (tx에 들어간 액션따라 허용 주소를 둔다던지) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
정도가 발생할 것으로 보여서 크게 걱정은 안했습니다. |
||
client = boto3.client("ssm", region_name=region) | ||
try: | ||
return client.get_parameter(Name=f"{stage}_9c_IAP_KMS_KEY_ID", WithDecryption=True)["Parameter"]["Value"] | ||
return client.get_parameter( | ||
Name=f"{stage}_9c_IAP{'_ADHOC' if adhoc else ''}_KMS_KEY_ID", | ||
WithDecryption=True | ||
)["Parameter"]["Value"] | ||
except Exception as e: | ||
logger.error(e) | ||
return None |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
from decimal import Decimal | ||
|
||
import pytest | ||
|
||
from common.lib9c.actions.issue_tokens_from_garage import IssueTokensFromGarage, FavIssueSpec, ItemIssueSpec | ||
from common.lib9c.models.currency import Currency | ||
from common.lib9c.models.fungible_asset_value import FungibleAssetValue | ||
|
||
TEST_ID = "0d0d9e0cbc1b11eeb0dc6fd71476142a" | ||
TEST_FUNGIBLE_ITEM_ID = "f8faf92c9c0d0e8e06694361ea87bfc8b29a8ae8de93044b98470a57636ed0e0" # Golden Dust | ||
TEST_FUNGIBLE_ITEM_BINARY = b'\xf8\xfa\xf9,\x9c\r\x0e\x8e\x06iCa\xea\x87\xbf\xc8\xb2\x9a\x8a\xe8\xde\x93\x04K\x98G\nWcn\xd0\xe0' | ||
ACTION_TEST_DATA = [ | ||
( | ||
{ | ||
"_id": TEST_ID, | ||
"values": [ | ||
FavIssueSpec(FungibleAssetValue.from_raw_data("Crystal", 18, amount=Decimal("1000"))) | ||
] | ||
}, | ||
[ | ||
[ | ||
[ | ||
{ | ||
"ticker": "Crystal", | ||
"decimalPlaces": b'\x12', | ||
"minters": None, | ||
}, | ||
1000 * 10 ** 18 | ||
], | ||
None | ||
], | ||
] | ||
), | ||
( | ||
{ | ||
"_id": TEST_ID, | ||
"values": [ | ||
ItemIssueSpec(TEST_FUNGIBLE_ITEM_ID, 42) | ||
] | ||
}, | ||
[ | ||
[ | ||
None, | ||
[ | ||
TEST_FUNGIBLE_ITEM_BINARY, | ||
42 | ||
] | ||
] | ||
] | ||
), | ||
( | ||
{ | ||
"_id": TEST_ID, | ||
"values": [ | ||
ItemIssueSpec("f8faf92c9c0d0e8e06694361ea87bfc8b29a8ae8de93044b98470a57636ed0e0", 42) | ||
] | ||
}, | ||
[ | ||
[ | ||
None, | ||
[ | ||
b'\xf8\xfa\xf9,\x9c\r\x0e\x8e\x06iCa\xea\x87\xbf\xc8\xb2\x9a\x8a\xe8\xde\x93\x04K\x98G\nWcn\xd0\xe0', | ||
42 | ||
] | ||
] | ||
] | ||
), | ||
( | ||
{ | ||
"_id": TEST_ID, | ||
"values": [ | ||
FavIssueSpec(FungibleAssetValue.from_raw_data("Crystal", 18, amount=Decimal("1000"))), | ||
ItemIssueSpec("f8faf92c9c0d0e8e06694361ea87bfc8b29a8ae8de93044b98470a57636ed0e0", 42) | ||
] | ||
}, | ||
[ | ||
[ | ||
[ | ||
{ | ||
"ticker": "Crystal", | ||
"decimalPlaces": b'\x12', | ||
"minters": None, | ||
}, | ||
1000 * 10 ** 18 | ||
], | ||
None | ||
], | ||
[ | ||
None, | ||
[ | ||
b'\xf8\xfa\xf9,\x9c\r\x0e\x8e\x06iCa\xea\x87\xbf\xc8\xb2\x9a\x8a\xe8\xde\x93\x04K\x98G\nWcn\xd0\xe0', | ||
42 | ||
] | ||
] | ||
] | ||
) | ||
] | ||
|
||
|
||
def test_fav_issue_spec(): | ||
fav = FungibleAssetValue(Currency("Crystal", 18), Decimal(42)) | ||
fav_issue_spec = FavIssueSpec(fav) | ||
assert fav_issue_spec.plain_value[0] == fav.plain_value | ||
|
||
|
||
@pytest.mark.parametrize("data", [TEST_FUNGIBLE_ITEM_ID, TEST_FUNGIBLE_ITEM_BINARY]) | ||
def test_item_issue_spec(data): | ||
item_issue_spec = ItemIssueSpec(data, 42) | ||
assert item_issue_spec.plain_value == [None, [TEST_FUNGIBLE_ITEM_BINARY, 42]] | ||
|
||
|
||
@pytest.mark.parametrize("test_data", ACTION_TEST_DATA) | ||
def test_action(test_data): | ||
data, expected = test_data | ||
action = IssueTokensFromGarage(**data) | ||
plain_value = action.plain_value | ||
values = plain_value["values"] | ||
|
||
assert plain_value["type_id"] == "issue_tokens_from_garage" | ||
assert values == expected |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
토큰 발행용 계정인걸까요? �ADHOC보단 별도의 정해진 이름이 있으면 좋을것같네요.(지금 당장 고쳐야할 건은 아닙니다.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네 garage > issue token 하는 계정입니다.
처음에 만든건 예전 IAP 초기에 수동지급 필요할 때 만들어서 adhoc 으로 한건데, 이름이야 뭐 고치면 됩니다 ㅋ